mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-27 16:17:34 +00:00
Feat: takeover & readonly policy (#5102)
* Feat: takeover & readonly Signed-off-by: Somefive <yd219913@alibaba-inc.com> * Feat: add tests Signed-off-by: Somefive <yd219913@alibaba-inc.com> * Feat: add cue def for read-only and take-over Signed-off-by: Somefive <yd219913@alibaba-inc.com> * Docs: add example doc Signed-off-by: Somefive <yd219913@alibaba-inc.com> Signed-off-by: Somefive <yd219913@alibaba-inc.com>
This commit is contained in:
+6
-1
@@ -59,8 +59,13 @@ type ApplyOnceStrategy struct {
|
||||
ApplyOnceAffectStrategy ApplyOnceAffectStrategy `json:"affect"`
|
||||
}
|
||||
|
||||
// Type the type name of the policy
|
||||
func (in *ApplyOncePolicySpec) Type() string {
|
||||
return ApplyOncePolicyType
|
||||
}
|
||||
|
||||
// FindStrategy find apply-once strategy for target resource
|
||||
func (in ApplyOncePolicySpec) FindStrategy(manifest *unstructured.Unstructured) *ApplyOnceStrategy {
|
||||
func (in *ApplyOncePolicySpec) FindStrategy(manifest *unstructured.Unstructured) *ApplyOnceStrategy {
|
||||
if !in.Enable {
|
||||
return nil
|
||||
}
|
||||
+6
-58
@@ -18,10 +18,6 @@ package v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/utils/pointer"
|
||||
"k8s.io/utils/strings/slices"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -57,59 +53,6 @@ type GarbageCollectPolicyRule struct {
|
||||
Strategy GarbageCollectStrategy `json:"strategy"`
|
||||
}
|
||||
|
||||
// ResourcePolicyRuleSelector select the targets of the rule
|
||||
// if multiple conditions are specified, combination logic is AND
|
||||
type ResourcePolicyRuleSelector struct {
|
||||
CompNames []string `json:"componentNames,omitempty"`
|
||||
CompTypes []string `json:"componentTypes,omitempty"`
|
||||
OAMResourceTypes []string `json:"oamTypes,omitempty"`
|
||||
TraitTypes []string `json:"traitTypes,omitempty"`
|
||||
ResourceTypes []string `json:"resourceTypes,omitempty"`
|
||||
ResourceNames []string `json:"resourceNames,omitempty"`
|
||||
}
|
||||
|
||||
// Match check if current rule selector match the target resource
|
||||
// If at least one condition is matched and no other condition failed (could be empty), return true
|
||||
// Otherwise, return false
|
||||
func (in *ResourcePolicyRuleSelector) Match(manifest *unstructured.Unstructured) bool {
|
||||
var compName, compType, oamType, traitType, resourceType, resourceName string
|
||||
if labels := manifest.GetLabels(); labels != nil {
|
||||
compName = labels[oam.LabelAppComponent]
|
||||
compType = labels[oam.WorkloadTypeLabel]
|
||||
oamType = labels[oam.LabelOAMResourceType]
|
||||
traitType = labels[oam.TraitTypeLabel]
|
||||
}
|
||||
resourceType = manifest.GetKind()
|
||||
resourceName = manifest.GetName()
|
||||
match := func(src []string, val string) (found *bool) {
|
||||
if len(src) == 0 {
|
||||
return nil
|
||||
}
|
||||
return pointer.Bool(val != "" && slices.Contains(src, val))
|
||||
}
|
||||
conditions := []*bool{
|
||||
match(in.CompNames, compName),
|
||||
match(in.CompTypes, compType),
|
||||
match(in.OAMResourceTypes, oamType),
|
||||
match(in.TraitTypes, traitType),
|
||||
match(in.ResourceTypes, resourceType),
|
||||
match(in.ResourceNames, resourceName),
|
||||
}
|
||||
hasMatched := false
|
||||
for _, cond := range conditions {
|
||||
// if any non-empty condition failed, return false
|
||||
if cond != nil && !*cond {
|
||||
return false
|
||||
}
|
||||
// if condition succeed, record it
|
||||
if cond != nil && *cond {
|
||||
hasMatched = true
|
||||
}
|
||||
}
|
||||
// if at least one condition is met, return true
|
||||
return hasMatched
|
||||
}
|
||||
|
||||
// GarbageCollectStrategy the strategy for target resource to recycle
|
||||
type GarbageCollectStrategy string
|
||||
|
||||
@@ -123,8 +66,13 @@ const (
|
||||
GarbageCollectStrategyOnAppUpdate GarbageCollectStrategy = "onAppUpdate"
|
||||
)
|
||||
|
||||
// Type the type name of the policy
|
||||
func (in *GarbageCollectPolicySpec) Type() string {
|
||||
return GarbageCollectPolicyType
|
||||
}
|
||||
|
||||
// FindStrategy find gc strategy for target resource
|
||||
func (in GarbageCollectPolicySpec) FindStrategy(manifest *unstructured.Unstructured) *GarbageCollectStrategy {
|
||||
func (in *GarbageCollectPolicySpec) FindStrategy(manifest *unstructured.Unstructured) *GarbageCollectStrategy {
|
||||
for _, rule := range in.Rules {
|
||||
if rule.Selector.Match(manifest) {
|
||||
return &rule.Strategy
|
||||
@@ -16,8 +16,6 @@ limitations under the License.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
const (
|
||||
// TopologyPolicyType refers to the type of topology policy
|
||||
TopologyPolicyType = "topology"
|
||||
@@ -25,8 +23,6 @@ const (
|
||||
OverridePolicyType = "override"
|
||||
// DebugPolicyType refers to the type of debug policy
|
||||
DebugPolicyType = "debug"
|
||||
// SharedResourcePolicyType refers to the type of shared resource policy
|
||||
SharedResourcePolicyType = "shared-resource"
|
||||
// ReplicationPolicyType refers to the type of replication policy
|
||||
ReplicationPolicyType = "replication"
|
||||
)
|
||||
@@ -64,26 +60,6 @@ type OverridePolicySpec struct {
|
||||
Selector []string `json:"selector,omitempty"`
|
||||
}
|
||||
|
||||
// SharedResourcePolicySpec defines the spec of shared-resource policy
|
||||
type SharedResourcePolicySpec struct {
|
||||
Rules []SharedResourcePolicyRule `json:"rules"`
|
||||
}
|
||||
|
||||
// SharedResourcePolicyRule defines the rule for sharing resources
|
||||
type SharedResourcePolicyRule struct {
|
||||
Selector ResourcePolicyRuleSelector `json:"selector"`
|
||||
}
|
||||
|
||||
// FindStrategy return if the target resource should be shared
|
||||
func (in SharedResourcePolicySpec) FindStrategy(manifest *unstructured.Unstructured) bool {
|
||||
for _, rule := range in.Rules {
|
||||
if rule.Selector.Match(manifest) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ReplicationPolicySpec defines the spec of replication policy
|
||||
// Override policy should be used together with replication policy to select the deployment target components
|
||||
type ReplicationPolicySpec struct {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
const (
|
||||
// ReadOnlyPolicyType refers to the type of read-only policy
|
||||
ReadOnlyPolicyType = "read-only"
|
||||
)
|
||||
|
||||
// ReadOnlyPolicySpec defines the spec of read-only policy
|
||||
type ReadOnlyPolicySpec struct {
|
||||
Rules []ReadOnlyPolicyRule `json:"rules"`
|
||||
}
|
||||
|
||||
// Type the type name of the policy
|
||||
func (in *ReadOnlyPolicySpec) Type() string {
|
||||
return ReadOnlyPolicyType
|
||||
}
|
||||
|
||||
// ReadOnlyPolicyRule defines the rule for read-only resources
|
||||
type ReadOnlyPolicyRule struct {
|
||||
Selector ResourcePolicyRuleSelector `json:"selector"`
|
||||
}
|
||||
|
||||
// FindStrategy return if the target resource is read-only
|
||||
func (in *ReadOnlyPolicySpec) FindStrategy(manifest *unstructured.Unstructured) bool {
|
||||
for _, rule := range in.Rules {
|
||||
if rule.Selector.Match(manifest) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/utils/pointer"
|
||||
stringslices "k8s.io/utils/strings/slices"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
)
|
||||
|
||||
// ResourcePolicyRuleSelector select the targets of the rule
|
||||
// if multiple conditions are specified, combination logic is AND
|
||||
type ResourcePolicyRuleSelector struct {
|
||||
CompNames []string `json:"componentNames,omitempty"`
|
||||
CompTypes []string `json:"componentTypes,omitempty"`
|
||||
OAMResourceTypes []string `json:"oamTypes,omitempty"`
|
||||
TraitTypes []string `json:"traitTypes,omitempty"`
|
||||
ResourceTypes []string `json:"resourceTypes,omitempty"`
|
||||
ResourceNames []string `json:"resourceNames,omitempty"`
|
||||
}
|
||||
|
||||
// Match check if current rule selector match the target resource
|
||||
// If at least one condition is matched and no other condition failed (could be empty), return true
|
||||
// Otherwise, return false
|
||||
func (in *ResourcePolicyRuleSelector) Match(manifest *unstructured.Unstructured) bool {
|
||||
var compName, compType, oamType, traitType, resourceType, resourceName string
|
||||
if labels := manifest.GetLabels(); labels != nil {
|
||||
compName = labels[oam.LabelAppComponent]
|
||||
compType = labels[oam.WorkloadTypeLabel]
|
||||
oamType = labels[oam.LabelOAMResourceType]
|
||||
traitType = labels[oam.TraitTypeLabel]
|
||||
}
|
||||
resourceType = manifest.GetKind()
|
||||
resourceName = manifest.GetName()
|
||||
match := func(src []string, val string) (found *bool) {
|
||||
if len(src) == 0 {
|
||||
return nil
|
||||
}
|
||||
return pointer.Bool(val != "" && stringslices.Contains(src, val))
|
||||
}
|
||||
conditions := []*bool{
|
||||
match(in.CompNames, compName),
|
||||
match(in.CompTypes, compType),
|
||||
match(in.OAMResourceTypes, oamType),
|
||||
match(in.TraitTypes, traitType),
|
||||
match(in.ResourceTypes, resourceType),
|
||||
match(in.ResourceNames, resourceName),
|
||||
}
|
||||
hasMatched := false
|
||||
for _, cond := range conditions {
|
||||
// if any non-empty condition failed, return false
|
||||
if cond != nil && !*cond {
|
||||
return false
|
||||
}
|
||||
// if condition succeed, record it
|
||||
if cond != nil && *cond {
|
||||
hasMatched = true
|
||||
}
|
||||
}
|
||||
// if at least one condition is met, return true
|
||||
return hasMatched
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
const (
|
||||
// SharedResourcePolicyType refers to the type of shared resource policy
|
||||
SharedResourcePolicyType = "shared-resource"
|
||||
)
|
||||
|
||||
// SharedResourcePolicySpec defines the spec of shared-resource policy
|
||||
type SharedResourcePolicySpec struct {
|
||||
Rules []SharedResourcePolicyRule `json:"rules"`
|
||||
}
|
||||
|
||||
// Type the type name of the policy
|
||||
func (in *SharedResourcePolicySpec) Type() string {
|
||||
return SharedResourcePolicyType
|
||||
}
|
||||
|
||||
// SharedResourcePolicyRule defines the rule for sharing resources
|
||||
type SharedResourcePolicyRule struct {
|
||||
Selector ResourcePolicyRuleSelector `json:"selector"`
|
||||
}
|
||||
|
||||
// FindStrategy return if the target resource should be shared
|
||||
func (in *SharedResourcePolicySpec) FindStrategy(manifest *unstructured.Unstructured) bool {
|
||||
for _, rule := range in.Rules {
|
||||
if rule.Selector.Match(manifest) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
const (
|
||||
// TakeOverPolicyType refers to the type of take-over policy
|
||||
TakeOverPolicyType = "take-over"
|
||||
)
|
||||
|
||||
// TakeOverPolicySpec defines the spec of take-over policy
|
||||
type TakeOverPolicySpec struct {
|
||||
Rules []TakeOverPolicyRule `json:"rules"`
|
||||
}
|
||||
|
||||
// Type the type name of the policy
|
||||
func (in *TakeOverPolicySpec) Type() string {
|
||||
return TakeOverPolicyType
|
||||
}
|
||||
|
||||
// TakeOverPolicyRule defines the rule for taking over resources
|
||||
type TakeOverPolicyRule struct {
|
||||
Selector ResourcePolicyRuleSelector `json:"selector"`
|
||||
}
|
||||
|
||||
// FindStrategy return if the target resource should be taken over
|
||||
func (in *TakeOverPolicySpec) FindStrategy(manifest *unstructured.Unstructured) bool {
|
||||
for _, rule := range in.Rules {
|
||||
if rule.Selector.Match(manifest) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -585,6 +585,44 @@ func (in *PolicyList) DeepCopyObject() runtime.Object {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ReadOnlyPolicyRule) DeepCopyInto(out *ReadOnlyPolicyRule) {
|
||||
*out = *in
|
||||
in.Selector.DeepCopyInto(&out.Selector)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReadOnlyPolicyRule.
|
||||
func (in *ReadOnlyPolicyRule) DeepCopy() *ReadOnlyPolicyRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ReadOnlyPolicyRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ReadOnlyPolicySpec) DeepCopyInto(out *ReadOnlyPolicySpec) {
|
||||
*out = *in
|
||||
if in.Rules != nil {
|
||||
in, out := &in.Rules, &out.Rules
|
||||
*out = make([]ReadOnlyPolicyRule, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReadOnlyPolicySpec.
|
||||
func (in *ReadOnlyPolicySpec) DeepCopy() *ReadOnlyPolicySpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ReadOnlyPolicySpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RefObjectsComponentSpec) DeepCopyInto(out *RefObjectsComponentSpec) {
|
||||
*out = *in
|
||||
@@ -720,6 +758,44 @@ func (in *SharedResourcePolicySpec) DeepCopy() *SharedResourcePolicySpec {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TakeOverPolicyRule) DeepCopyInto(out *TakeOverPolicyRule) {
|
||||
*out = *in
|
||||
in.Selector.DeepCopyInto(&out.Selector)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TakeOverPolicyRule.
|
||||
func (in *TakeOverPolicyRule) DeepCopy() *TakeOverPolicyRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TakeOverPolicyRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TakeOverPolicySpec) DeepCopyInto(out *TakeOverPolicySpec) {
|
||||
*out = *in
|
||||
if in.Rules != nil {
|
||||
in, out := &in.Rules, &out.Rules
|
||||
*out = make([]TakeOverPolicyRule, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TakeOverPolicySpec.
|
||||
func (in *TakeOverPolicySpec) DeepCopy() *TakeOverPolicySpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TakeOverPolicySpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TopologyPolicySpec) DeepCopyInto(out *TopologyPolicySpec) {
|
||||
*out = *in
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/read-only.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: PolicyDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Configure the resources to be read-only in the application (no update / state-keep).
|
||||
name: read-only
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
#PolicyRule: {
|
||||
// +usage=Specify how to select the targets of the rule
|
||||
selector: [...#RuleSelector]
|
||||
}
|
||||
#RuleSelector: {
|
||||
// +usage=Select resources by component names
|
||||
componentNames?: [...string]
|
||||
// +usage=Select resources by component types
|
||||
componentTypes?: [...string]
|
||||
// +usage=Select resources by oamTypes (COMPONENT or TRAIT)
|
||||
oamTypes?: [...string]
|
||||
// +usage=Select resources by trait types
|
||||
traitTypes?: [...string]
|
||||
// +usage=Select resources by resource types (like Deployment)
|
||||
resourceTypes?: [...string]
|
||||
// +usage=Select resources by their names
|
||||
resourceNames?: [...string]
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Specify the list of rules to control read only strategy at resource level.
|
||||
// The selected resource will be read-only to the current application. If the target resource does
|
||||
// not exist, error will be raised.
|
||||
rules?: [...#PolicyRule]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/take-over.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: PolicyDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Configure the resources to be able to take over when it belongs to no application.
|
||||
name: take-over
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
#PolicyRule: {
|
||||
// +usage=Specify how to select the targets of the rule
|
||||
selector: [...#RuleSelector]
|
||||
}
|
||||
#RuleSelector: {
|
||||
// +usage=Select resources by component names
|
||||
componentNames?: [...string]
|
||||
// +usage=Select resources by component types
|
||||
componentTypes?: [...string]
|
||||
// +usage=Select resources by oamTypes (COMPONENT or TRAIT)
|
||||
oamTypes?: [...string]
|
||||
// +usage=Select resources by trait types
|
||||
traitTypes?: [...string]
|
||||
// +usage=Select resources by resource types (like Deployment)
|
||||
resourceTypes?: [...string]
|
||||
// +usage=Select resources by their names
|
||||
resourceNames?: [...string]
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Specify the list of rules to control take over strategy at resource level.
|
||||
// The selected resource will be able to be taken over by the current application when the resource belongs to no
|
||||
// one.
|
||||
rules?: [...#PolicyRule]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/read-only.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: PolicyDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Configure the resources to be read-only in the application (no update / state-keep).
|
||||
name: read-only
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
#PolicyRule: {
|
||||
// +usage=Specify how to select the targets of the rule
|
||||
selector: [...#RuleSelector]
|
||||
}
|
||||
#RuleSelector: {
|
||||
// +usage=Select resources by component names
|
||||
componentNames?: [...string]
|
||||
// +usage=Select resources by component types
|
||||
componentTypes?: [...string]
|
||||
// +usage=Select resources by oamTypes (COMPONENT or TRAIT)
|
||||
oamTypes?: [...string]
|
||||
// +usage=Select resources by trait types
|
||||
traitTypes?: [...string]
|
||||
// +usage=Select resources by resource types (like Deployment)
|
||||
resourceTypes?: [...string]
|
||||
// +usage=Select resources by their names
|
||||
resourceNames?: [...string]
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Specify the list of rules to control read only strategy at resource level.
|
||||
// The selected resource will be read-only to the current application. If the target resource does
|
||||
// not exist, error will be raised.
|
||||
rules?: [...#PolicyRule]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/take-over.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: PolicyDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Configure the resources to be able to take over when it belongs to no application.
|
||||
name: take-over
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
#PolicyRule: {
|
||||
// +usage=Specify how to select the targets of the rule
|
||||
selector: [...#RuleSelector]
|
||||
}
|
||||
#RuleSelector: {
|
||||
// +usage=Select resources by component names
|
||||
componentNames?: [...string]
|
||||
// +usage=Select resources by component types
|
||||
componentTypes?: [...string]
|
||||
// +usage=Select resources by oamTypes (COMPONENT or TRAIT)
|
||||
oamTypes?: [...string]
|
||||
// +usage=Select resources by trait types
|
||||
traitTypes?: [...string]
|
||||
// +usage=Select resources by resource types (like Deployment)
|
||||
resourceTypes?: [...string]
|
||||
// +usage=Select resources by their names
|
||||
resourceNames?: [...string]
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Specify the list of rules to control take over strategy at resource level.
|
||||
// The selected resource will be able to be taken over by the current application when the resource belongs to no
|
||||
// one.
|
||||
rules?: [...#PolicyRule]
|
||||
}
|
||||
|
||||
@@ -87,10 +87,10 @@ require (
|
||||
github.com/xlab/treeprint v1.1.0
|
||||
go.mongodb.org/mongo-driver v1.5.1
|
||||
go.uber.org/zap v1.21.0
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be
|
||||
golang.org/x/crypto v0.1.0
|
||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||
golang.org/x/text v0.3.8
|
||||
golang.org/x/term v0.1.0
|
||||
golang.org/x/text v0.4.0
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
@@ -294,12 +294,12 @@ require (
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.7.0 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220818022119-ed83ed61efb9 // indirect
|
||||
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c // indirect
|
||||
golang.org/x/mod v0.6.0 // indirect
|
||||
golang.org/x/net v0.1.0 // indirect
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
golang.org/x/tools v0.2.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/grpc v1.48.0 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
|
||||
@@ -2201,8 +2201,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A=
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -2246,8 +2246,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220818022119-ed83ed61efb9 h1:VtCrPQXM5Wo9l7XN64SjBMczl48j8mkP+2e3OhYlz+0=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220818022119-ed83ed61efb9/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -2327,8 +2327,8 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c h1:yKufUcDwucU5urd+50/Opbt4AYpqthk7wHpHok8f1lo=
|
||||
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -2520,15 +2520,16 @@ golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -2541,8 +2542,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -2685,8 +2686,8 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM=
|
||||
golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -389,6 +389,8 @@ func (p *Parser) parsePoliciesFromRevision(ctx context.Context, af *Appfile) (er
|
||||
case v1alpha1.GarbageCollectPolicyType:
|
||||
case v1alpha1.ApplyOncePolicyType:
|
||||
case v1alpha1.SharedResourcePolicyType:
|
||||
case v1alpha1.TakeOverPolicyType:
|
||||
case v1alpha1.ReadOnlyPolicyType:
|
||||
case v1alpha1.EnvBindingPolicyType:
|
||||
case v1alpha1.TopologyPolicyType:
|
||||
case v1alpha1.OverridePolicyType:
|
||||
@@ -418,6 +420,8 @@ func (p *Parser) parsePolicies(ctx context.Context, af *Appfile) (err error) {
|
||||
case v1alpha1.GarbageCollectPolicyType:
|
||||
case v1alpha1.ApplyOncePolicyType:
|
||||
case v1alpha1.SharedResourcePolicyType:
|
||||
case v1alpha1.TakeOverPolicyType:
|
||||
case v1alpha1.ReadOnlyPolicyType:
|
||||
case v1alpha1.EnvBindingPolicyType:
|
||||
case v1alpha1.TopologyPolicyType:
|
||||
case v1alpha1.ReplicationPolicyType:
|
||||
|
||||
@@ -17,7 +17,6 @@ limitations under the License.
|
||||
package definition
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
@@ -171,7 +170,7 @@ func (wd *workloadDef) getTemplateContext(ctx process.Context, cli client.Reader
|
||||
return nil, err
|
||||
}
|
||||
// workload main resource will have a unique label("app.oam.dev/resourceType"="WORKLOAD") in per component/app level
|
||||
object, err := getResourceFromObj(ctx.GetCtx(), componentWorkload, cli, accessor.For(componentWorkload), util.MergeMapOverrideWithDst(map[string]string{
|
||||
object, err := getResourceFromObj(ctx, componentWorkload, cli, accessor.For(componentWorkload), util.MergeMapOverrideWithDst(map[string]string{
|
||||
oam.LabelOAMResourceType: oam.ResourceTypeWorkload,
|
||||
}, commonLabels), "")
|
||||
if err != nil {
|
||||
@@ -191,7 +190,7 @@ func (wd *workloadDef) getTemplateContext(ctx process.Context, cli client.Reader
|
||||
return nil, err
|
||||
}
|
||||
// AuxiliaryWorkload will have a unique label("trait.oam.dev/resource"="name of outputs") in per component/app level
|
||||
object, err := getResourceFromObj(ctx.GetCtx(), traitRef, cli, accessor.For(traitRef), util.MergeMapOverrideWithDst(map[string]string{
|
||||
object, err := getResourceFromObj(ctx, traitRef, cli, accessor.For(traitRef), util.MergeMapOverrideWithDst(map[string]string{
|
||||
oam.TraitTypeLabel: AuxiliaryWorkload,
|
||||
}, commonLabels), assist.Name)
|
||||
if err != nil {
|
||||
@@ -452,7 +451,7 @@ func (td *traitDef) getTemplateContext(ctx process.Context, cli client.Reader, a
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
object, err := getResourceFromObj(ctx.GetCtx(), traitRef, cli, accessor.For(traitRef), util.MergeMapOverrideWithDst(map[string]string{
|
||||
object, err := getResourceFromObj(ctx, traitRef, cli, accessor.For(traitRef), util.MergeMapOverrideWithDst(map[string]string{
|
||||
oam.TraitTypeLabel: assist.Type,
|
||||
}, commonLabels), assist.Name)
|
||||
if err != nil {
|
||||
@@ -484,18 +483,18 @@ func (td *traitDef) HealthCheck(ctx process.Context, cli client.Client, accessor
|
||||
return checkHealth(templateContext, healthPolicyTemplate, parameter)
|
||||
}
|
||||
|
||||
func getResourceFromObj(ctx context.Context, obj *unstructured.Unstructured, client client.Reader, namespace string, labels map[string]string, outputsResource string) (map[string]interface{}, error) {
|
||||
func getResourceFromObj(ctx process.Context, obj *unstructured.Unstructured, client client.Reader, namespace string, labels map[string]string, outputsResource string) (map[string]interface{}, error) {
|
||||
if outputsResource != "" {
|
||||
labels[oam.TraitResource] = outputsResource
|
||||
}
|
||||
if obj.GetName() != "" {
|
||||
u, err := util.GetObjectGivenGVKAndName(ctx, client, obj.GroupVersionKind(), namespace, obj.GetName())
|
||||
u, err := util.GetObjectGivenGVKAndName(ctx.GetCtx(), client, obj.GroupVersionKind(), namespace, obj.GetName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return u.Object, nil
|
||||
}
|
||||
list, err := util.GetObjectsGivenGVKAndLabels(ctx, client, obj.GroupVersionKind(), namespace, labels)
|
||||
list, err := util.GetObjectsGivenGVKAndLabels(ctx.GetCtx(), client, obj.GroupVersionKind(), namespace, labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -507,5 +506,12 @@ func getResourceFromObj(ctx context.Context, obj *unstructured.Unstructured, cli
|
||||
return v.Object, nil
|
||||
}
|
||||
}
|
||||
if ctxName := ctx.GetData(model.ContextName).(string); ctxName != "" {
|
||||
u, err := util.GetObjectGivenGVKAndName(ctx.GetCtx(), client, obj.GroupVersionKind(), namespace, ctxName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return u.Object, nil
|
||||
}
|
||||
return nil, errors.Errorf("no resources found gvk(%v) labels(%v)", obj.GroupVersionKind(), labels)
|
||||
}
|
||||
|
||||
+13
-36
@@ -18,49 +18,26 @@ package policy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
)
|
||||
|
||||
// parsePolicy parse policy for application
|
||||
func parsePolicy(app *v1beta1.Application, policyType string, policySpec interface{}) (exists bool, err error) {
|
||||
type typer[T any] interface {
|
||||
*T
|
||||
Type() string
|
||||
}
|
||||
|
||||
// ParsePolicy parse policy for the given type
|
||||
func ParsePolicy[T any, P typer[T]](app *v1beta1.Application) (*T, error) {
|
||||
spec := new(T)
|
||||
for _, policy := range app.Spec.Policies {
|
||||
if policy.Type == policyType && policy.Properties != nil && policy.Properties.Raw != nil {
|
||||
if err := json.Unmarshal(policy.Properties.Raw, policySpec); err != nil {
|
||||
return true, errors.Wrapf(err, "invalid %s policy: %s", policy.Type, policy.Name)
|
||||
if policy.Type == P(spec).Type() && policy.Properties != nil && policy.Properties.Raw != nil {
|
||||
if err := json.Unmarshal(policy.Properties.Raw, spec); err != nil {
|
||||
return nil, fmt.Errorf("invalid %s policy %s: %w", policy.Type, policy.Name, err)
|
||||
}
|
||||
return true, nil
|
||||
return spec, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// ParseGarbageCollectPolicy parse garbage-collect policy
|
||||
func ParseGarbageCollectPolicy(app *v1beta1.Application) (*v1alpha1.GarbageCollectPolicySpec, error) {
|
||||
spec := &v1alpha1.GarbageCollectPolicySpec{}
|
||||
if exists, err := parsePolicy(app, v1alpha1.GarbageCollectPolicyType, spec); exists {
|
||||
return spec, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ParseApplyOncePolicy parse apply-once policy
|
||||
func ParseApplyOncePolicy(app *v1beta1.Application) (*v1alpha1.ApplyOncePolicySpec, error) {
|
||||
spec := &v1alpha1.ApplyOncePolicySpec{}
|
||||
if exists, err := parsePolicy(app, v1alpha1.ApplyOncePolicyType, spec); exists {
|
||||
return spec, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ParseSharedResourcePolicy parse shared-resource policy
|
||||
func ParseSharedResourcePolicy(app *v1beta1.Application) (*v1alpha1.SharedResourcePolicySpec, error) {
|
||||
spec := &v1alpha1.SharedResourcePolicySpec{}
|
||||
if exists, err := parsePolicy(app, v1alpha1.SharedResourcePolicyType, spec); exists {
|
||||
return spec, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
+12
-12
@@ -32,14 +32,14 @@ func TestParseGarbageCollectPolicy(t *testing.T) {
|
||||
app := &v1beta1.Application{Spec: v1beta1.ApplicationSpec{
|
||||
Policies: []v1beta1.AppPolicy{{Type: "example"}},
|
||||
}}
|
||||
spec, err := ParseGarbageCollectPolicy(app)
|
||||
spec, err := ParsePolicy[v1alpha1.GarbageCollectPolicySpec](app)
|
||||
r.NoError(err)
|
||||
r.Nil(spec)
|
||||
app.Spec.Policies = append(app.Spec.Policies, v1beta1.AppPolicy{
|
||||
Type: "garbage-collect",
|
||||
Properties: &runtime.RawExtension{Raw: []byte("bad value")},
|
||||
})
|
||||
_, err = ParseGarbageCollectPolicy(app)
|
||||
_, err = ParsePolicy[v1alpha1.GarbageCollectPolicySpec](app)
|
||||
r.Error(err)
|
||||
policySpec := &v1alpha1.GarbageCollectPolicySpec{
|
||||
KeepLegacyResource: false,
|
||||
@@ -54,7 +54,7 @@ func TestParseGarbageCollectPolicy(t *testing.T) {
|
||||
bs, err := json.Marshal(policySpec)
|
||||
r.NoError(err)
|
||||
app.Spec.Policies[1].Properties.Raw = bs
|
||||
spec, err = ParseGarbageCollectPolicy(app)
|
||||
spec, err = ParsePolicy[v1alpha1.GarbageCollectPolicySpec](app)
|
||||
r.NoError(err)
|
||||
r.Equal(policySpec, spec)
|
||||
}
|
||||
@@ -64,20 +64,20 @@ func TestParseApplyOncePolicy(t *testing.T) {
|
||||
app := &v1beta1.Application{Spec: v1beta1.ApplicationSpec{
|
||||
Policies: []v1beta1.AppPolicy{{Type: "example"}},
|
||||
}}
|
||||
spec, err := ParseApplyOncePolicy(app)
|
||||
spec, err := ParsePolicy[v1alpha1.ApplyOncePolicySpec](app)
|
||||
r.NoError(err)
|
||||
r.Nil(spec)
|
||||
app.Spec.Policies = append(app.Spec.Policies, v1beta1.AppPolicy{
|
||||
Type: "apply-once",
|
||||
Properties: &runtime.RawExtension{Raw: []byte("bad value")},
|
||||
})
|
||||
_, err = ParseApplyOncePolicy(app)
|
||||
_, err = ParsePolicy[v1alpha1.ApplyOncePolicySpec](app)
|
||||
r.Error(err)
|
||||
policySpec := &v1alpha1.ApplyOncePolicySpec{Enable: true}
|
||||
bs, err := json.Marshal(policySpec)
|
||||
r.NoError(err)
|
||||
app.Spec.Policies[1].Properties.Raw = bs
|
||||
spec, err = ParseApplyOncePolicy(app)
|
||||
spec, err = ParsePolicy[v1alpha1.ApplyOncePolicySpec](app)
|
||||
r.NoError(err)
|
||||
r.Equal(policySpec, spec)
|
||||
}
|
||||
@@ -87,14 +87,14 @@ func TestParseSharedResourcePolicy(t *testing.T) {
|
||||
app := &v1beta1.Application{Spec: v1beta1.ApplicationSpec{
|
||||
Policies: []v1beta1.AppPolicy{{Type: "example"}},
|
||||
}}
|
||||
spec, err := ParseSharedResourcePolicy(app)
|
||||
spec, err := ParsePolicy[v1alpha1.SharedResourcePolicySpec](app)
|
||||
r.NoError(err)
|
||||
r.Nil(spec)
|
||||
app.Spec.Policies = append(app.Spec.Policies, v1beta1.AppPolicy{
|
||||
Type: "shared-resource",
|
||||
Properties: &runtime.RawExtension{Raw: []byte("bad value")},
|
||||
})
|
||||
_, err = ParseSharedResourcePolicy(app)
|
||||
_, err = ParsePolicy[v1alpha1.SharedResourcePolicySpec](app)
|
||||
r.Error(err)
|
||||
policySpec := &v1alpha1.SharedResourcePolicySpec{
|
||||
Rules: []v1alpha1.SharedResourcePolicyRule{{
|
||||
@@ -103,7 +103,7 @@ func TestParseSharedResourcePolicy(t *testing.T) {
|
||||
bs, err := json.Marshal(policySpec)
|
||||
r.NoError(err)
|
||||
app.Spec.Policies[1].Properties.Raw = bs
|
||||
spec, err = ParseSharedResourcePolicy(app)
|
||||
spec, err = ParsePolicy[v1alpha1.SharedResourcePolicySpec](app)
|
||||
r.NoError(err)
|
||||
r.Equal(policySpec, spec)
|
||||
}
|
||||
@@ -112,9 +112,9 @@ func TestParsePolicy(t *testing.T) {
|
||||
r := require.New(t)
|
||||
// Test skipping empty policy
|
||||
app := &v1beta1.Application{Spec: v1beta1.ApplicationSpec{
|
||||
Policies: []v1beta1.AppPolicy{{Type: "example", Name: "s", Properties: nil}},
|
||||
Policies: []v1beta1.AppPolicy{{Type: v1alpha1.GarbageCollectPolicyType, Name: "s", Properties: nil}},
|
||||
}}
|
||||
exists, err := parsePolicy(app, "example", nil)
|
||||
r.False(exists, "empty policy should not be included")
|
||||
exists, err := ParsePolicy[v1alpha1.GarbageCollectPolicySpec](app)
|
||||
r.Nil(exists)
|
||||
r.NoError(err)
|
||||
}
|
||||
|
||||
@@ -142,6 +142,12 @@ func (h *resourceKeeper) dispatch(ctx context.Context, manifests []*unstructured
|
||||
if h.isShared(manifest) {
|
||||
ao = append([]apply.ApplyOption{apply.SharedByApp(h.app)}, ao...)
|
||||
}
|
||||
if h.isReadOnly(manifest) {
|
||||
ao = append([]apply.ApplyOption{apply.ReadOnly()}, ao...)
|
||||
}
|
||||
if h.canTakeOver(manifest) {
|
||||
ao = append([]apply.ApplyOption{apply.TakeOver()}, ao...)
|
||||
}
|
||||
manifest, err := ApplyStrategies(applyCtx, h, manifest, v1alpha1.ApplyOnceStrategyOnAppUpdate)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to apply once policy for application %s,%s", h.app.Name, err.Error())
|
||||
|
||||
@@ -61,6 +61,8 @@ type resourceKeeper struct {
|
||||
applyOncePolicy *v1alpha1.ApplyOncePolicySpec
|
||||
garbageCollectPolicy *v1alpha1.GarbageCollectPolicySpec
|
||||
sharedResourcePolicy *v1alpha1.SharedResourcePolicySpec
|
||||
takeOverPolicy *v1alpha1.TakeOverPolicySpec
|
||||
readOnlyPolicy *v1alpha1.ReadOnlyPolicySpec
|
||||
|
||||
cache *resourceCache
|
||||
}
|
||||
@@ -93,18 +95,24 @@ func (h *resourceKeeper) getComponentRevisionRT(ctx context.Context) (crRT *v1be
|
||||
}
|
||||
|
||||
func (h *resourceKeeper) parseApplicationResourcePolicy() (err error) {
|
||||
if h.applyOncePolicy, err = policy.ParseApplyOncePolicy(h.app); err != nil {
|
||||
if h.applyOncePolicy, err = policy.ParsePolicy[v1alpha1.ApplyOncePolicySpec](h.app); err != nil {
|
||||
return errors.Wrapf(err, "failed to parse apply-once policy")
|
||||
}
|
||||
if h.applyOncePolicy == nil && metav1.HasLabel(h.app.ObjectMeta, oam.LabelAddonName) {
|
||||
h.applyOncePolicy = &v1alpha1.ApplyOncePolicySpec{Enable: true}
|
||||
}
|
||||
if h.garbageCollectPolicy, err = policy.ParseGarbageCollectPolicy(h.app); err != nil {
|
||||
if h.garbageCollectPolicy, err = policy.ParsePolicy[v1alpha1.GarbageCollectPolicySpec](h.app); err != nil {
|
||||
return errors.Wrapf(err, "failed to parse garbage-collect policy")
|
||||
}
|
||||
if h.sharedResourcePolicy, err = policy.ParseSharedResourcePolicy(h.app); err != nil {
|
||||
if h.sharedResourcePolicy, err = policy.ParsePolicy[v1alpha1.SharedResourcePolicySpec](h.app); err != nil {
|
||||
return errors.Wrapf(err, "failed to parse shared-resource policy")
|
||||
}
|
||||
if h.takeOverPolicy, err = policy.ParsePolicy[v1alpha1.TakeOverPolicySpec](h.app); err != nil {
|
||||
return errors.Wrapf(err, "failed to parse take-over policy")
|
||||
}
|
||||
if h.readOnlyPolicy, err = policy.ParsePolicy[v1alpha1.ReadOnlyPolicySpec](h.app); err != nil {
|
||||
return errors.Wrapf(err, "failed to parse read-only policy")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,12 @@ func (h *resourceKeeper) StateKeep(ctx context.Context) error {
|
||||
if h.isShared(manifest) {
|
||||
ao = append([]apply.ApplyOption{apply.SharedByApp(h.app)}, ao...)
|
||||
}
|
||||
if h.isReadOnly(manifest) {
|
||||
ao = append([]apply.ApplyOption{apply.ReadOnly()}, ao...)
|
||||
}
|
||||
if h.canTakeOver(manifest) {
|
||||
ao = append([]apply.ApplyOption{apply.TakeOver()}, ao...)
|
||||
}
|
||||
if err = h.applicator.Apply(applyCtx, manifest, ao...); err != nil {
|
||||
return errors.Wrapf(err, "failed to re-apply resource %s from resourcetracker %s", mr.ResourceKey(), rt.Name)
|
||||
}
|
||||
|
||||
@@ -37,3 +37,17 @@ func (h *resourceKeeper) isShared(manifest *unstructured.Unstructured) bool {
|
||||
}
|
||||
return h.sharedResourcePolicy.FindStrategy(manifest)
|
||||
}
|
||||
|
||||
func (h *resourceKeeper) canTakeOver(manifest *unstructured.Unstructured) bool {
|
||||
if h.takeOverPolicy == nil {
|
||||
return false
|
||||
}
|
||||
return h.takeOverPolicy.FindStrategy(manifest)
|
||||
}
|
||||
|
||||
func (h *resourceKeeper) isReadOnly(manifest *unstructured.Unstructured) bool {
|
||||
if h.readOnlyPolicy == nil {
|
||||
return false
|
||||
}
|
||||
return h.readOnlyPolicy.FindStrategy(manifest)
|
||||
}
|
||||
|
||||
@@ -56,6 +56,8 @@ type Applicator interface {
|
||||
}
|
||||
|
||||
type applyAction struct {
|
||||
takeOver bool
|
||||
readOnly bool
|
||||
isShared bool
|
||||
skipUpdate bool
|
||||
updateAnnotation bool
|
||||
@@ -228,6 +230,9 @@ func createOrGetExisting(ctx context.Context, act *applyAction, c client.Client,
|
||||
if err := executeApplyOptions(act, nil, desired, ao); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if act.readOnly {
|
||||
return nil, fmt.Errorf("cannot create %s (%s) in read-only mode", desired.GetObjectKind().GroupVersionKind().Kind, desired.GetName())
|
||||
}
|
||||
if act.updateAnnotation {
|
||||
if err := addLastAppliedConfigAnnotation(desired); err != nil {
|
||||
return nil, err
|
||||
@@ -297,6 +302,23 @@ func NotUpdateRenderHashEqual() ApplyOption {
|
||||
}
|
||||
}
|
||||
|
||||
// ReadOnly skip apply fo the resource
|
||||
func ReadOnly() ApplyOption {
|
||||
return func(act *applyAction, _, _ client.Object) error {
|
||||
act.readOnly = true
|
||||
act.skipUpdate = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// TakeOver allow take over resources without app owner
|
||||
func TakeOver() ApplyOption {
|
||||
return func(act *applyAction, _, _ client.Object) error {
|
||||
act.takeOver = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MustBeControllableBy requires that the new object is controllable by an
|
||||
// object with the supplied UID. An object is controllable if its controller
|
||||
// reference includes the supplied UID.
|
||||
@@ -319,14 +341,14 @@ func MustBeControllableBy(u types.UID) ApplyOption {
|
||||
// MustBeControlledByApp requires that the new object is controllable by versioned resourcetracker
|
||||
func MustBeControlledByApp(app *v1beta1.Application) ApplyOption {
|
||||
return func(act *applyAction, existing, _ client.Object) error {
|
||||
if existing == nil || act.isShared {
|
||||
if existing == nil || act.isShared || act.readOnly {
|
||||
return nil
|
||||
}
|
||||
appKey, controlledBy := GetAppKey(app), GetControlledBy(existing)
|
||||
// if the existing object has no resource version, it means this resource is an API response not directly from
|
||||
// an etcd object but from some external services, such as vela-prism. Then the response does not necessarily
|
||||
// contain the owner
|
||||
if controlledBy == "" && !utilfeature.DefaultMutableFeatureGate.Enabled(features.LegacyResourceOwnerValidation) && existing.GetResourceVersion() != "" {
|
||||
if controlledBy == "" && !utilfeature.DefaultMutableFeatureGate.Enabled(features.LegacyResourceOwnerValidation) && existing.GetResourceVersion() != "" && !act.takeOver {
|
||||
return fmt.Errorf("%s %s/%s exists but not managed by any application now", existing.GetObjectKind().GroupVersionKind().Kind, existing.GetNamespace(), existing.GetName())
|
||||
}
|
||||
if controlledBy != "" && controlledBy != appKey {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: read-only
|
||||
spec:
|
||||
components:
|
||||
- name: busybox
|
||||
type: worker
|
||||
properties:
|
||||
image: busybox
|
||||
cmd:
|
||||
- sleep
|
||||
- '1000000'
|
||||
policies:
|
||||
- type: read-only
|
||||
name: read-only
|
||||
properties:
|
||||
rules:
|
||||
- selector:
|
||||
resourceTypes: ["Deployment"]
|
||||
```
|
||||
@@ -0,0 +1,23 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: take-over
|
||||
spec:
|
||||
components:
|
||||
- name: busybox
|
||||
type: k8s-objects
|
||||
properties:
|
||||
objects:
|
||||
- apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: busybox-ref
|
||||
policies:
|
||||
- type: take-over
|
||||
name: take-over
|
||||
properties:
|
||||
rules:
|
||||
- selector:
|
||||
resourceTypes: ["Deployment"]
|
||||
```
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
@@ -714,5 +715,74 @@ var _ = Describe("Test multicluster scenario", func() {
|
||||
Expect(cm.Data["cluster"]).Should(Equal("cluster-worker"))
|
||||
Expect(k8sClient.Delete(hubCtx, def)).Should(Succeed())
|
||||
})
|
||||
|
||||
It("Test application with read-only policy", func() {
|
||||
By("create deployment")
|
||||
bs, err := os.ReadFile("./testdata/app/standalone/deployment-busybox.yaml")
|
||||
Expect(err).Should(Succeed())
|
||||
deploy := &appsv1.Deployment{}
|
||||
Expect(yaml.Unmarshal(bs, deploy)).Should(Succeed())
|
||||
deploy.SetNamespace(namespace)
|
||||
Expect(k8sClient.Create(hubCtx, deploy)).Should(Succeed())
|
||||
By("create application")
|
||||
bs, err = os.ReadFile("./testdata/app/app-readonly.yaml")
|
||||
Expect(err).Should(Succeed())
|
||||
app := &v1beta1.Application{}
|
||||
Expect(yaml.Unmarshal(bs, app)).Should(Succeed())
|
||||
app.SetNamespace(namespace)
|
||||
Expect(k8sClient.Create(hubCtx, app)).Should(Succeed())
|
||||
Eventually(func(g Gomega) {
|
||||
g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed())
|
||||
g.Expect(app.Status.Workflow).ShouldNot(BeNil())
|
||||
g.Expect(app.Status.Workflow.Steps[0].Phase).Should(Equal(workflowv1alpha1.WorkflowStepPhaseFailed))
|
||||
}, 20*time.Second).Should(Succeed())
|
||||
By("update application")
|
||||
Eventually(func(g Gomega) {
|
||||
g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed())
|
||||
app.Spec.Components[0].Name = "busybox-ref"
|
||||
g.Expect(k8sClient.Update(hubCtx, app)).Should(Succeed())
|
||||
}, 20*time.Second).Should(Succeed())
|
||||
Eventually(func(g Gomega) {
|
||||
g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed())
|
||||
g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning))
|
||||
}, 20*time.Second).Should(Succeed())
|
||||
By("delete application")
|
||||
appKey := client.ObjectKeyFromObject(app)
|
||||
deployKey := client.ObjectKeyFromObject(deploy)
|
||||
Expect(k8sClient.Delete(hubCtx, app)).Should(Succeed())
|
||||
Eventually(func(g Gomega) {
|
||||
g.Expect(kerrors.IsNotFound(k8sClient.Get(hubCtx, appKey, app))).Should(BeTrue())
|
||||
}, 20*time.Second).Should(Succeed())
|
||||
Expect(k8sClient.Get(hubCtx, deployKey, deploy)).Should(Succeed())
|
||||
})
|
||||
|
||||
It("Test application with take-over policy", func() {
|
||||
By("create deployment")
|
||||
bs, err := os.ReadFile("./testdata/app/standalone/deployment-busybox.yaml")
|
||||
Expect(err).Should(Succeed())
|
||||
deploy := &appsv1.Deployment{}
|
||||
Expect(yaml.Unmarshal(bs, deploy)).Should(Succeed())
|
||||
deploy.SetNamespace(namespace)
|
||||
Expect(k8sClient.Create(hubCtx, deploy)).Should(Succeed())
|
||||
By("create application")
|
||||
bs, err = os.ReadFile("./testdata/app/app-takeover.yaml")
|
||||
Expect(err).Should(Succeed())
|
||||
app := &v1beta1.Application{}
|
||||
Expect(yaml.Unmarshal(bs, app)).Should(Succeed())
|
||||
app.SetNamespace(namespace)
|
||||
Expect(k8sClient.Create(hubCtx, app)).Should(Succeed())
|
||||
Eventually(func(g Gomega) {
|
||||
g.Expect(k8sClient.Get(hubCtx, client.ObjectKeyFromObject(app), app)).Should(Succeed())
|
||||
g.Expect(app.Status.Phase).Should(Equal(common.ApplicationRunning))
|
||||
}, 20*time.Second).Should(Succeed())
|
||||
By("delete application")
|
||||
appKey := client.ObjectKeyFromObject(app)
|
||||
deployKey := client.ObjectKeyFromObject(deploy)
|
||||
Expect(k8sClient.Delete(hubCtx, app)).Should(Succeed())
|
||||
Eventually(func(g Gomega) {
|
||||
g.Expect(kerrors.IsNotFound(k8sClient.Get(hubCtx, appKey, app))).Should(BeTrue())
|
||||
g.Expect(kerrors.IsNotFound(k8sClient.Get(hubCtx, deployKey, deploy))).Should(BeTrue())
|
||||
}, 20*time.Second).Should(Succeed())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: read-only
|
||||
spec:
|
||||
components:
|
||||
- name: busybox
|
||||
type: worker
|
||||
properties:
|
||||
image: busybox
|
||||
cmd:
|
||||
- sleep
|
||||
- '1000000'
|
||||
policies:
|
||||
- type: read-only
|
||||
name: read-only
|
||||
properties:
|
||||
rules:
|
||||
- selector:
|
||||
resourceTypes: ["Deployment"]
|
||||
@@ -0,0 +1,21 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: take-over
|
||||
spec:
|
||||
components:
|
||||
- name: busybox
|
||||
type: k8s-objects
|
||||
properties:
|
||||
objects:
|
||||
- apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: busybox-ref
|
||||
policies:
|
||||
- type: take-over
|
||||
name: take-over
|
||||
properties:
|
||||
rules:
|
||||
- selector:
|
||||
resourceTypes: ["Deployment"]
|
||||
@@ -0,0 +1,36 @@
|
||||
"read-only": {
|
||||
annotations: {}
|
||||
description: "Configure the resources to be read-only in the application (no update / state-keep)."
|
||||
labels: {}
|
||||
attributes: {}
|
||||
type: "policy"
|
||||
}
|
||||
|
||||
template: {
|
||||
#PolicyRule: {
|
||||
// +usage=Specify how to select the targets of the rule
|
||||
selector: [...#RuleSelector]
|
||||
}
|
||||
|
||||
#RuleSelector: {
|
||||
// +usage=Select resources by component names
|
||||
componentNames?: [...string]
|
||||
// +usage=Select resources by component types
|
||||
componentTypes?: [...string]
|
||||
// +usage=Select resources by oamTypes (COMPONENT or TRAIT)
|
||||
oamTypes?: [...string]
|
||||
// +usage=Select resources by trait types
|
||||
traitTypes?: [...string]
|
||||
// +usage=Select resources by resource types (like Deployment)
|
||||
resourceTypes?: [...string]
|
||||
// +usage=Select resources by their names
|
||||
resourceNames?: [...string]
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Specify the list of rules to control read only strategy at resource level.
|
||||
// The selected resource will be read-only to the current application. If the target resource does
|
||||
// not exist, error will be raised.
|
||||
rules?: [...#PolicyRule]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
"take-over": {
|
||||
annotations: {}
|
||||
description: "Configure the resources to be able to take over when it belongs to no application."
|
||||
labels: {}
|
||||
attributes: {}
|
||||
type: "policy"
|
||||
}
|
||||
|
||||
template: {
|
||||
#PolicyRule: {
|
||||
// +usage=Specify how to select the targets of the rule
|
||||
selector: [...#RuleSelector]
|
||||
}
|
||||
|
||||
#RuleSelector: {
|
||||
// +usage=Select resources by component names
|
||||
componentNames?: [...string]
|
||||
// +usage=Select resources by component types
|
||||
componentTypes?: [...string]
|
||||
// +usage=Select resources by oamTypes (COMPONENT or TRAIT)
|
||||
oamTypes?: [...string]
|
||||
// +usage=Select resources by trait types
|
||||
traitTypes?: [...string]
|
||||
// +usage=Select resources by resource types (like Deployment)
|
||||
resourceTypes?: [...string]
|
||||
// +usage=Select resources by their names
|
||||
resourceNames?: [...string]
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Specify the list of rules to control take over strategy at resource level.
|
||||
// The selected resource will be able to be taken over by the current application when the resource belongs to no
|
||||
// one.
|
||||
rules?: [...#PolicyRule]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user