mirror of
https://github.com/open-cluster-management-io/ocm.git
synced 2026-05-14 05:07:48 +00:00
Add spoke operator
This commit is contained in:
3
Makefile
3
Makefile
@@ -11,12 +11,13 @@ include $(addprefix ./vendor/github.com/openshift/build-machinery-go/make/, \
|
||||
)
|
||||
|
||||
$(call add-bindata,hub,./manifests/hub/...,bindata,bindata,./pkg/operators/hub/bindata/bindata.go)
|
||||
$(call add-bindata,spoke,./manifests/spoke/...,bindata,bindata,./pkg/operators/spoke/bindata/bindata.go)
|
||||
|
||||
copy-crd:
|
||||
cp ./vendor/github.com/open-cluster-management/api/cluster/v1/*.yaml ./manifests/hub/
|
||||
cp ./vendor/github.com/open-cluster-management/api/work/v1/*.yaml ./manifests/hub/
|
||||
|
||||
update-all: copy-crd update
|
||||
update-all: copy-crd update-bindata-hub update-bindata-spoke
|
||||
|
||||
clean:
|
||||
$(RM) ./nucleus
|
||||
|
||||
2
go.mod
2
go.mod
@@ -4,7 +4,7 @@ go 1.13
|
||||
|
||||
require (
|
||||
github.com/jteeuwen/go-bindata v3.0.8-0.20151023091102-a0ff2567cfb7+incompatible
|
||||
github.com/open-cluster-management/api v0.0.0-20200506150956-355c9d6ef16b
|
||||
github.com/open-cluster-management/api v0.0.0-20200512021938-5f0d5c12ea67
|
||||
github.com/openshift/api v0.0.0-20200326160804-ecb9283fe820
|
||||
github.com/openshift/build-machinery-go v0.0.0-20200211121458-5e3d6e570160
|
||||
github.com/openshift/library-go v0.0.0-20200414135834-ccc4bb27d032
|
||||
|
||||
4
go.sum
4
go.sum
@@ -279,8 +279,8 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/open-cluster-management/api v0.0.0-20200506150956-355c9d6ef16b h1:vaOPmEZRgtXSa7SBkyrZKR7HStXTAAv1kQoc/nlZ66g=
|
||||
github.com/open-cluster-management/api v0.0.0-20200506150956-355c9d6ef16b/go.mod h1:RgKeB8PJ7upe2QXy/MpCejU/xm2G6/i0Y+/itWuPugs=
|
||||
github.com/open-cluster-management/api v0.0.0-20200512021938-5f0d5c12ea67 h1:JHbmXcawfV/Flb+csFz+FFHOG9EfEfcUH5cggNX8Yu4=
|
||||
github.com/open-cluster-management/api v0.0.0-20200512021938-5f0d5c12ea67/go.mod h1:RgKeB8PJ7upe2QXy/MpCejU/xm2G6/i0Y+/itWuPugs=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/runc v0.0.0-20191031171055-b133feaeeb2e/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
|
||||
@@ -50,7 +50,11 @@ spec:
|
||||
to be deployed on the spoke cluster.
|
||||
type: array
|
||||
items:
|
||||
description: Manifest represents a resource to be deployed on
|
||||
spoke cluster
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
x-kubernetes-embedded-resource: true
|
||||
status:
|
||||
description: Status represents the current status of work
|
||||
type: object
|
||||
13
manifests/spoke/spoke-clusterrolebinding.yaml
Normal file
13
manifests/spoke/spoke-clusterrolebinding.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: system:open-cluster-management:{{ .SpokeCoreName }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ .SpokeCoreName }}-sa
|
||||
namespace: {{ .SpokeCoreNamespace }}
|
||||
|
||||
55
manifests/spoke/spoke-registration-deployment.yaml
Normal file
55
manifests/spoke/spoke-registration-deployment.yaml
Normal file
@@ -0,0 +1,55 @@
|
||||
kind: Deployment
|
||||
apiVersion: apps/v1
|
||||
metadata:
|
||||
name: {{ .SpokeCoreName }}-registration-agent
|
||||
namespace: {{ .SpokeCoreNamespace }}
|
||||
labels:
|
||||
app: spoke-registration-agent
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spoke-registration-agent
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: spoke-registration-agent
|
||||
spec:
|
||||
serviceAccountName: {{ .SpokeCoreName }}-sa
|
||||
containers:
|
||||
- name: spoke-agent
|
||||
image: {{ .RegistrationImage }}
|
||||
imagePullPolicy: IfNotPresent
|
||||
args:
|
||||
- "/registration"
|
||||
- "agent"
|
||||
- "--cluster-name={{ .ClusterName }}"
|
||||
- "--bootstrap-kubeconfig=/spoke/bootstrap/kubeconfig"
|
||||
- "--spoke-external-server-url={{ .ExternalServerURL }}"
|
||||
volumeMounts:
|
||||
- name: bootstrap-secret
|
||||
mountPath: "/spoke/bootstrap"
|
||||
readOnly: true
|
||||
- name: hub-kubeconfig-secret
|
||||
mountPath: "/spoke/hub-kubeconfig"
|
||||
readOnly: true
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
scheme: HTTPS
|
||||
port: 443
|
||||
initialDelaySeconds: 2
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
scheme: HTTPS
|
||||
port: 443
|
||||
initialDelaySeconds: 2
|
||||
volumes:
|
||||
- name: bootstrap-secret
|
||||
secret:
|
||||
secretName: {{ .BootStrapKubeConfigSecret }}
|
||||
- name: hub-kubeconfig-secret
|
||||
secret:
|
||||
secretName: {{ .HubKubeConfigSecret }}
|
||||
5
manifests/spoke/spoke-serviceaccount.yaml
Normal file
5
manifests/spoke/spoke-serviceaccount.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ .SpokeCoreName }}-sa
|
||||
namespace: {{ .SpokeCoreNamespace }}
|
||||
48
manifests/spoke/spoke-work-deployment.yaml
Normal file
48
manifests/spoke/spoke-work-deployment.yaml
Normal file
@@ -0,0 +1,48 @@
|
||||
kind: Deployment
|
||||
apiVersion: apps/v1
|
||||
metadata:
|
||||
name: {{ .SpokeCoreName }}-work-agent
|
||||
namespace: {{ .SpokeCoreNamespace }}
|
||||
labels:
|
||||
app: spoke-work-agent
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spoke-work-agent
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: spoke-work-agent
|
||||
spec:
|
||||
serviceAccountName: {{ .SpokeCoreName }}-sa
|
||||
containers:
|
||||
- name: spoke-agent
|
||||
image: {{ .WorkImage }}
|
||||
imagePullPolicy: IfNotPresent
|
||||
args:
|
||||
- "/work"
|
||||
- "agent"
|
||||
- "--cluster-name={{ .ClusterName }}"
|
||||
- "--kubeconfig=/spoke/hub-kubeconfig"
|
||||
volumeMounts:
|
||||
- name: hub-kubeconfig-secret
|
||||
mountPath: "/spoke/hub-kubeconfig"
|
||||
readOnly: true
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
scheme: HTTPS
|
||||
port: 443
|
||||
initialDelaySeconds: 2
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
scheme: HTTPS
|
||||
port: 443
|
||||
initialDelaySeconds: 2
|
||||
volumes:
|
||||
- name: hub-kubeconfig-secret
|
||||
secret:
|
||||
secretName: {{ .HubKubeConfigSecret }}
|
||||
@@ -9,10 +9,10 @@ import (
|
||||
"github.com/open-cluster-management/nucleus/pkg/version"
|
||||
)
|
||||
|
||||
// NewOperator generatee a command to start workload agent
|
||||
// NewOperatorCmd generatee a command to start workload agent
|
||||
func NewOperatorCmd() *cobra.Command {
|
||||
cmd := controllercmd.
|
||||
NewControllerCommandConfig("operator", version.Get(), operators.RunNucleusOperator).
|
||||
NewControllerCommandConfig("nucleus-operator", version.Get(), operators.RunNucleusOperator).
|
||||
NewCommand()
|
||||
cmd.Use = "operator"
|
||||
cmd.Short = "Start the nucleus operator"
|
||||
|
||||
@@ -96,3 +96,53 @@ func UpdateNucleusHubConditionFn(conds ...nucleusapiv1.StatusCondition) UpdateNu
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type UpdateNucleusSpokeStatusFunc func(status *nucleusapiv1.SpokeCoreStatus) error
|
||||
|
||||
func UpdateNucleusSpokeStatus(
|
||||
ctx context.Context,
|
||||
client nucleusv1client.SpokeCoreInterface,
|
||||
nucleusSpokeCoreName string,
|
||||
updateFuncs ...UpdateNucleusSpokeStatusFunc) (*nucleusapiv1.SpokeCoreStatus, bool, error) {
|
||||
updated := false
|
||||
var updatedSpokeClusterStatus *nucleusapiv1.SpokeCoreStatus
|
||||
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
||||
spokeCore, err := client.Get(ctx, nucleusSpokeCoreName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oldStatus := &spokeCore.Status
|
||||
|
||||
newStatus := oldStatus.DeepCopy()
|
||||
for _, update := range updateFuncs {
|
||||
if err := update(newStatus); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if equality.Semantic.DeepEqual(oldStatus, newStatus) {
|
||||
// We return the newStatus which is a deep copy of oldStatus but with all update funcs applied.
|
||||
updatedSpokeClusterStatus = newStatus
|
||||
return nil
|
||||
}
|
||||
|
||||
spokeCore.Status = *newStatus
|
||||
updatedSpokeCluster, err := client.UpdateStatus(ctx, spokeCore, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedSpokeClusterStatus = &updatedSpokeCluster.Status
|
||||
updated = err == nil
|
||||
return err
|
||||
})
|
||||
|
||||
return updatedSpokeClusterStatus, updated, err
|
||||
}
|
||||
|
||||
func UpdateNucleusSpokeConditionFn(conds ...nucleusapiv1.StatusCondition) UpdateNucleusSpokeStatusFunc {
|
||||
return func(oldStatus *nucleusapiv1.SpokeCoreStatus) error {
|
||||
for _, cond := range conds {
|
||||
SetNucleusCondition(&oldStatus.Conditions, cond)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,14 +73,22 @@ func TestUpdateStatusCondition(t *testing.T) {
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
fakeClusterClient := nucleusfake.NewSimpleClientset(&nucleusapiv1.HubCore{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "testspokecluster"},
|
||||
Status: nucleusapiv1.HubCoreStatus{
|
||||
Conditions: c.startingConditions,
|
||||
fakeClusterClient := nucleusfake.NewSimpleClientset(
|
||||
&nucleusapiv1.HubCore{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "testspokecluster"},
|
||||
Status: nucleusapiv1.HubCoreStatus{
|
||||
Conditions: c.startingConditions,
|
||||
},
|
||||
},
|
||||
})
|
||||
&nucleusapiv1.SpokeCore{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "testspokecluster"},
|
||||
Status: nucleusapiv1.SpokeCoreStatus{
|
||||
Conditions: c.startingConditions,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
status, updated, err := UpdateNucleusHubStatus(
|
||||
hubstatus, updated, err := UpdateNucleusHubStatus(
|
||||
context.TODO(),
|
||||
fakeClusterClient.NucleusV1().HubCores(),
|
||||
"testspokecluster",
|
||||
@@ -92,14 +100,36 @@ func TestUpdateStatusCondition(t *testing.T) {
|
||||
if updated != c.expextedUpdated {
|
||||
t.Errorf("expected %t, but %t", c.expextedUpdated, updated)
|
||||
}
|
||||
|
||||
spokestatus, updated, err := UpdateNucleusSpokeStatus(
|
||||
context.TODO(),
|
||||
fakeClusterClient.NucleusV1().SpokeCores(),
|
||||
"testspokecluster",
|
||||
UpdateNucleusSpokeConditionFn(c.newCondition),
|
||||
)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected err: %v", err)
|
||||
}
|
||||
if updated != c.expextedUpdated {
|
||||
t.Errorf("expected %t, but %t", c.expextedUpdated, updated)
|
||||
}
|
||||
|
||||
for i := range c.expectedConditions {
|
||||
expected := c.expectedConditions[i]
|
||||
actual := status.Conditions[i]
|
||||
hubactual := hubstatus.Conditions[i]
|
||||
if expected.LastTransitionTime == (metav1.Time{}) {
|
||||
actual.LastTransitionTime = metav1.Time{}
|
||||
hubactual.LastTransitionTime = metav1.Time{}
|
||||
}
|
||||
if !equality.Semantic.DeepEqual(expected, actual) {
|
||||
t.Errorf(diff.ObjectDiff(expected, actual))
|
||||
if !equality.Semantic.DeepEqual(expected, hubactual) {
|
||||
t.Errorf(diff.ObjectDiff(expected, hubactual))
|
||||
}
|
||||
|
||||
spokeactual := spokestatus.Conditions[i]
|
||||
if expected.LastTransitionTime == (metav1.Time{}) {
|
||||
spokeactual.LastTransitionTime = metav1.Time{}
|
||||
}
|
||||
if !equality.Semantic.DeepEqual(expected, spokeactual) {
|
||||
t.Errorf(diff.ObjectDiff(expected, spokeactual))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by go-bindata.
|
||||
// sources:
|
||||
// manifests/hub/0000_00_clusters.open-cluster-management.io_spokeclusters.crd.yaml
|
||||
// manifests/hub/0000_00_work.open-cluster-management.io_workloads.crd.yaml
|
||||
// manifests/hub/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml
|
||||
// manifests/hub/hub-clusterrole.yaml
|
||||
// manifests/hub/hub-clusterrolebinding.yaml
|
||||
// manifests/hub/hub-deployment.yaml
|
||||
@@ -201,7 +201,7 @@ func manifestsHub0000_00_clustersOpenClusterManagementIo_spokeclustersCrdYaml()
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _manifestsHub0000_00_workOpenClusterManagementIo_workloadsCrdYaml = []byte(`apiVersion: apiextensions.k8s.io/v1beta1
|
||||
var _manifestsHub0000_00_workOpenClusterManagementIo_manifestworksCrdYaml = []byte(`apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
@@ -253,7 +253,11 @@ spec:
|
||||
to be deployed on the spoke cluster.
|
||||
type: array
|
||||
items:
|
||||
description: Manifest represents a resource to be deployed on
|
||||
spoke cluster
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
x-kubernetes-embedded-resource: true
|
||||
status:
|
||||
description: Status represents the current status of work
|
||||
type: object
|
||||
@@ -385,17 +389,17 @@ status:
|
||||
storedVersions: []
|
||||
`)
|
||||
|
||||
func manifestsHub0000_00_workOpenClusterManagementIo_workloadsCrdYamlBytes() ([]byte, error) {
|
||||
return _manifestsHub0000_00_workOpenClusterManagementIo_workloadsCrdYaml, nil
|
||||
func manifestsHub0000_00_workOpenClusterManagementIo_manifestworksCrdYamlBytes() ([]byte, error) {
|
||||
return _manifestsHub0000_00_workOpenClusterManagementIo_manifestworksCrdYaml, nil
|
||||
}
|
||||
|
||||
func manifestsHub0000_00_workOpenClusterManagementIo_workloadsCrdYaml() (*asset, error) {
|
||||
bytes, err := manifestsHub0000_00_workOpenClusterManagementIo_workloadsCrdYamlBytes()
|
||||
func manifestsHub0000_00_workOpenClusterManagementIo_manifestworksCrdYaml() (*asset, error) {
|
||||
bytes, err := manifestsHub0000_00_workOpenClusterManagementIo_manifestworksCrdYamlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "manifests/hub/0000_00_work.open-cluster-management.io_workloads.crd.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
|
||||
info := bindataFileInfo{name: "manifests/hub/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -627,7 +631,7 @@ func AssetNames() []string {
|
||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||
var _bindata = map[string]func() (*asset, error){
|
||||
"manifests/hub/0000_00_clusters.open-cluster-management.io_spokeclusters.crd.yaml": manifestsHub0000_00_clustersOpenClusterManagementIo_spokeclustersCrdYaml,
|
||||
"manifests/hub/0000_00_work.open-cluster-management.io_workloads.crd.yaml": manifestsHub0000_00_workOpenClusterManagementIo_workloadsCrdYaml,
|
||||
"manifests/hub/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml": manifestsHub0000_00_workOpenClusterManagementIo_manifestworksCrdYaml,
|
||||
"manifests/hub/hub-clusterrole.yaml": manifestsHubHubClusterroleYaml,
|
||||
"manifests/hub/hub-clusterrolebinding.yaml": manifestsHubHubClusterrolebindingYaml,
|
||||
"manifests/hub/hub-deployment.yaml": manifestsHubHubDeploymentYaml,
|
||||
@@ -679,7 +683,7 @@ var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"manifests": {nil, map[string]*bintree{
|
||||
"hub": {nil, map[string]*bintree{
|
||||
"0000_00_clusters.open-cluster-management.io_spokeclusters.crd.yaml": {manifestsHub0000_00_clustersOpenClusterManagementIo_spokeclustersCrdYaml, map[string]*bintree{}},
|
||||
"0000_00_work.open-cluster-management.io_workloads.crd.yaml": {manifestsHub0000_00_workOpenClusterManagementIo_workloadsCrdYaml, map[string]*bintree{}},
|
||||
"0000_00_work.open-cluster-management.io_manifestworks.crd.yaml": {manifestsHub0000_00_workOpenClusterManagementIo_manifestworksCrdYaml, map[string]*bintree{}},
|
||||
"hub-clusterrole.yaml": {manifestsHubHubClusterroleYaml, map[string]*bintree{}},
|
||||
"hub-clusterrolebinding.yaml": {manifestsHubHubClusterrolebindingYaml, map[string]*bintree{}},
|
||||
"hub-deployment.yaml": {manifestsHubHubDeploymentYaml, map[string]*bintree{}},
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
@@ -77,7 +78,10 @@ func NewNucleusHubController(
|
||||
|
||||
return factory.New().WithSync(controller.sync).
|
||||
ResyncEvery(3*time.Minute).
|
||||
WithInformers(nucleusInformer.Informer()).
|
||||
WithInformersQueueKeyFunc(func(obj runtime.Object) string {
|
||||
accessor, _ := meta.Accessor(obj)
|
||||
return accessor.GetName()
|
||||
}, nucleusInformer.Informer()).
|
||||
ToController("NucleusHubController", recorder)
|
||||
}
|
||||
|
||||
@@ -93,6 +97,10 @@ func (n *nucleusHubController) sync(ctx context.Context, controllerContext facto
|
||||
klog.V(4).Infof("Reconciling HubCore %q", hubCoreName)
|
||||
|
||||
hubCore, err := n.nucleusLister.Get(hubCoreName)
|
||||
if errors.IsNotFound(err) {
|
||||
// HubCore not found, could have been deleted, do nothing.
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -137,7 +145,7 @@ func (n *nucleusHubController) sync(ctx context.Context, controllerContext facto
|
||||
return assets.MustCreateAssetFromTemplate(name, bindata.MustAsset(filepath.Join("", name)), config).Data, nil
|
||||
},
|
||||
"manifests/hub/0000_00_clusters.open-cluster-management.io_spokeclusters.crd.yaml",
|
||||
"manifests/hub/0000_00_work.open-cluster-management.io_workloads.crd.yaml",
|
||||
"manifests/hub/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml",
|
||||
"manifests/hub/hub-clusterrole.yaml",
|
||||
"manifests/hub/hub-clusterrolebinding.yaml",
|
||||
"manifests/hub/hub-namespace.yaml",
|
||||
|
||||
@@ -40,11 +40,15 @@ func RunNucleusOperator(ctx context.Context, controllerContext *controllercmd.Co
|
||||
nucleusClient.NucleusV1().HubCores(),
|
||||
nucleusInformer.Nucleus().V1().HubCores(),
|
||||
controllerContext.EventRecorder)
|
||||
agentController := spoke.NewNucleusAgentController(kubeClient, controllerContext.EventRecorder)
|
||||
spokeController := spoke.NewNucleusSpokeController(
|
||||
kubeClient,
|
||||
nucleusClient.NucleusV1().SpokeCores(),
|
||||
nucleusInformer.Nucleus().V1().SpokeCores(),
|
||||
controllerContext.EventRecorder)
|
||||
|
||||
go nucleusInformer.Start(ctx.Done())
|
||||
go hubcontroller.Run(ctx, 1)
|
||||
go agentController.Run(ctx, 1)
|
||||
go spokeController.Run(ctx, 1)
|
||||
<-ctx.Done()
|
||||
return nil
|
||||
}
|
||||
|
||||
393
pkg/operators/spoke/bindata/bindata.go
Normal file
393
pkg/operators/spoke/bindata/bindata.go
Normal file
@@ -0,0 +1,393 @@
|
||||
// Code generated by go-bindata.
|
||||
// sources:
|
||||
// manifests/spoke/spoke-clusterrolebinding.yaml
|
||||
// manifests/spoke/spoke-registration-deployment.yaml
|
||||
// manifests/spoke/spoke-serviceaccount.yaml
|
||||
// manifests/spoke/spoke-work-deployment.yaml
|
||||
// DO NOT EDIT!
|
||||
|
||||
package bindata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type asset struct {
|
||||
bytes []byte
|
||||
info os.FileInfo
|
||||
}
|
||||
|
||||
type bindataFileInfo struct {
|
||||
name string
|
||||
size int64
|
||||
mode os.FileMode
|
||||
modTime time.Time
|
||||
}
|
||||
|
||||
func (fi bindataFileInfo) Name() string {
|
||||
return fi.name
|
||||
}
|
||||
func (fi bindataFileInfo) Size() int64 {
|
||||
return fi.size
|
||||
}
|
||||
func (fi bindataFileInfo) Mode() os.FileMode {
|
||||
return fi.mode
|
||||
}
|
||||
func (fi bindataFileInfo) ModTime() time.Time {
|
||||
return fi.modTime
|
||||
}
|
||||
func (fi bindataFileInfo) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
func (fi bindataFileInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
var _manifestsSpokeSpokeClusterrolebindingYaml = []byte(`apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: system:open-cluster-management:{{ .SpokeCoreName }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ .SpokeCoreName }}-sa
|
||||
namespace: {{ .SpokeCoreNamespace }}
|
||||
`)
|
||||
|
||||
func manifestsSpokeSpokeClusterrolebindingYamlBytes() ([]byte, error) {
|
||||
return _manifestsSpokeSpokeClusterrolebindingYaml, nil
|
||||
}
|
||||
|
||||
func manifestsSpokeSpokeClusterrolebindingYaml() (*asset, error) {
|
||||
bytes, err := manifestsSpokeSpokeClusterrolebindingYamlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "manifests/spoke/spoke-clusterrolebinding.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _manifestsSpokeSpokeRegistrationDeploymentYaml = []byte(`kind: Deployment
|
||||
apiVersion: apps/v1
|
||||
metadata:
|
||||
name: {{ .SpokeCoreName }}-registration-agent
|
||||
namespace: {{ .SpokeCoreNamespace }}
|
||||
labels:
|
||||
app: spoke-registration-agent
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spoke-registration-agent
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: spoke-registration-agent
|
||||
spec:
|
||||
serviceAccountName: {{ .SpokeCoreName }}-sa
|
||||
containers:
|
||||
- name: spoke-agent
|
||||
image: {{ .RegistrationImage }}
|
||||
imagePullPolicy: IfNotPresent
|
||||
args:
|
||||
- "/registration"
|
||||
- "agent"
|
||||
- "--cluster-name={{ .ClusterName }}"
|
||||
- "--bootstrap-kubeconfig=/spoke/bootstrap/kubeconfig"
|
||||
- "--spoke-external-server-url={{ .ExternalServerURL }}"
|
||||
volumeMounts:
|
||||
- name: bootstrap-secret
|
||||
mountPath: "/spoke/bootstrap"
|
||||
readOnly: true
|
||||
- name: hub-kubeconfig-secret
|
||||
mountPath: "/spoke/hub-kubeconfig"
|
||||
readOnly: true
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
scheme: HTTPS
|
||||
port: 443
|
||||
initialDelaySeconds: 2
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
scheme: HTTPS
|
||||
port: 443
|
||||
initialDelaySeconds: 2
|
||||
volumes:
|
||||
- name: bootstrap-secret
|
||||
secret:
|
||||
secretName: {{ .BootStrapKubeConfigSecret }}
|
||||
- name: hub-kubeconfig-secret
|
||||
secret:
|
||||
secretName: {{ .HubKubeConfigSecret }}
|
||||
`)
|
||||
|
||||
func manifestsSpokeSpokeRegistrationDeploymentYamlBytes() ([]byte, error) {
|
||||
return _manifestsSpokeSpokeRegistrationDeploymentYaml, nil
|
||||
}
|
||||
|
||||
func manifestsSpokeSpokeRegistrationDeploymentYaml() (*asset, error) {
|
||||
bytes, err := manifestsSpokeSpokeRegistrationDeploymentYamlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "manifests/spoke/spoke-registration-deployment.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _manifestsSpokeSpokeServiceaccountYaml = []byte(`apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ .SpokeCoreName }}-sa
|
||||
namespace: {{ .SpokeCoreNamespace }}
|
||||
`)
|
||||
|
||||
func manifestsSpokeSpokeServiceaccountYamlBytes() ([]byte, error) {
|
||||
return _manifestsSpokeSpokeServiceaccountYaml, nil
|
||||
}
|
||||
|
||||
func manifestsSpokeSpokeServiceaccountYaml() (*asset, error) {
|
||||
bytes, err := manifestsSpokeSpokeServiceaccountYamlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "manifests/spoke/spoke-serviceaccount.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _manifestsSpokeSpokeWorkDeploymentYaml = []byte(`kind: Deployment
|
||||
apiVersion: apps/v1
|
||||
metadata:
|
||||
name: {{ .SpokeCoreName }}-work-agent
|
||||
namespace: {{ .SpokeCoreNamespace }}
|
||||
labels:
|
||||
app: spoke-work-agent
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spoke-work-agent
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: spoke-work-agent
|
||||
spec:
|
||||
serviceAccountName: {{ .SpokeCoreName }}-sa
|
||||
containers:
|
||||
- name: spoke-agent
|
||||
image: {{ .WorkImage }}
|
||||
imagePullPolicy: IfNotPresent
|
||||
args:
|
||||
- "/work"
|
||||
- "agent"
|
||||
- "--cluster-name={{ .ClusterName }}"
|
||||
- "--kubeconfig=/spoke/hub-kubeconfig"
|
||||
volumeMounts:
|
||||
- name: hub-kubeconfig-secret
|
||||
mountPath: "/spoke/hub-kubeconfig"
|
||||
readOnly: true
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
scheme: HTTPS
|
||||
port: 443
|
||||
initialDelaySeconds: 2
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
scheme: HTTPS
|
||||
port: 443
|
||||
initialDelaySeconds: 2
|
||||
volumes:
|
||||
- name: hub-kubeconfig-secret
|
||||
secret:
|
||||
secretName: {{ .HubKubeConfigSecret }}
|
||||
`)
|
||||
|
||||
func manifestsSpokeSpokeWorkDeploymentYamlBytes() ([]byte, error) {
|
||||
return _manifestsSpokeSpokeWorkDeploymentYaml, nil
|
||||
}
|
||||
|
||||
func manifestsSpokeSpokeWorkDeploymentYaml() (*asset, error) {
|
||||
bytes, err := manifestsSpokeSpokeWorkDeploymentYamlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "manifests/spoke/spoke-work-deployment.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// Asset loads and returns the asset for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func Asset(name string) ([]byte, error) {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
|
||||
}
|
||||
return a.bytes, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
|
||||
// MustAsset is like Asset but panics when Asset would return an error.
|
||||
// It simplifies safe initialization of global variables.
|
||||
func MustAsset(name string) []byte {
|
||||
a, err := Asset(name)
|
||||
if err != nil {
|
||||
panic("asset: Asset(" + name + "): " + err.Error())
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// AssetInfo loads and returns the asset info for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func AssetInfo(name string) (os.FileInfo, error) {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
|
||||
}
|
||||
return a.info, nil
|
||||
}
|
||||
return nil, fmt.Errorf("AssetInfo %s not found", name)
|
||||
}
|
||||
|
||||
// AssetNames returns the names of the assets.
|
||||
func AssetNames() []string {
|
||||
names := make([]string, 0, len(_bindata))
|
||||
for name := range _bindata {
|
||||
names = append(names, name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||
var _bindata = map[string]func() (*asset, error){
|
||||
"manifests/spoke/spoke-clusterrolebinding.yaml": manifestsSpokeSpokeClusterrolebindingYaml,
|
||||
"manifests/spoke/spoke-registration-deployment.yaml": manifestsSpokeSpokeRegistrationDeploymentYaml,
|
||||
"manifests/spoke/spoke-serviceaccount.yaml": manifestsSpokeSpokeServiceaccountYaml,
|
||||
"manifests/spoke/spoke-work-deployment.yaml": manifestsSpokeSpokeWorkDeploymentYaml,
|
||||
}
|
||||
|
||||
// AssetDir returns the file names below a certain
|
||||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||
// AssetDir("") will return []string{"data"}.
|
||||
func AssetDir(name string) ([]string, error) {
|
||||
node := _bintree
|
||||
if len(name) != 0 {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
pathList := strings.Split(cannonicalName, "/")
|
||||
for _, p := range pathList {
|
||||
node = node.Children[p]
|
||||
if node == nil {
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.Func != nil {
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
rv := make([]string, 0, len(node.Children))
|
||||
for childName := range node.Children {
|
||||
rv = append(rv, childName)
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
type bintree struct {
|
||||
Func func() (*asset, error)
|
||||
Children map[string]*bintree
|
||||
}
|
||||
|
||||
var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"manifests": {nil, map[string]*bintree{
|
||||
"spoke": {nil, map[string]*bintree{
|
||||
"spoke-clusterrolebinding.yaml": {manifestsSpokeSpokeClusterrolebindingYaml, map[string]*bintree{}},
|
||||
"spoke-registration-deployment.yaml": {manifestsSpokeSpokeRegistrationDeploymentYaml, map[string]*bintree{}},
|
||||
"spoke-serviceaccount.yaml": {manifestsSpokeSpokeServiceaccountYaml, map[string]*bintree{}},
|
||||
"spoke-work-deployment.yaml": {manifestsSpokeSpokeWorkDeploymentYaml, map[string]*bintree{}},
|
||||
}},
|
||||
}},
|
||||
}}
|
||||
|
||||
// RestoreAsset restores an asset under the given directory
|
||||
func RestoreAsset(dir, name string) error {
|
||||
data, err := Asset(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := AssetInfo(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RestoreAssets restores an asset under the given directory recursively
|
||||
func RestoreAssets(dir, name string) error {
|
||||
children, err := AssetDir(name)
|
||||
// File
|
||||
if err != nil {
|
||||
return RestoreAsset(dir, name)
|
||||
}
|
||||
// Dir
|
||||
for _, child := range children {
|
||||
err = RestoreAssets(dir, filepath.Join(name, child))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func _filePath(dir, name string) string {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
|
||||
}
|
||||
@@ -2,28 +2,395 @@ package spoke
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/klog"
|
||||
|
||||
"github.com/openshift/api"
|
||||
"github.com/openshift/library-go/pkg/controller/factory"
|
||||
"github.com/openshift/library-go/pkg/operator/events"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
|
||||
"github.com/openshift/library-go/pkg/assets"
|
||||
"github.com/openshift/library-go/pkg/operator/resource/resourceapply"
|
||||
operatorhelpers "github.com/openshift/library-go/pkg/operator/v1helpers"
|
||||
|
||||
nucleusv1client "github.com/open-cluster-management/api/client/nucleus/clientset/versioned/typed/nucleus/v1"
|
||||
nucleusinformer "github.com/open-cluster-management/api/client/nucleus/informers/externalversions/nucleus/v1"
|
||||
nucleuslister "github.com/open-cluster-management/api/client/nucleus/listers/nucleus/v1"
|
||||
nucleusapiv1 "github.com/open-cluster-management/api/nucleus/v1"
|
||||
"github.com/open-cluster-management/nucleus/pkg/helpers"
|
||||
"github.com/open-cluster-management/nucleus/pkg/operators/spoke/bindata"
|
||||
)
|
||||
|
||||
type nucleusAgentController struct {
|
||||
kubeClient kubernetes.Interface
|
||||
const (
|
||||
nucleusSpokeFinalizer = "nucleus.open-cluster-management.io/spoke-core-cleanup"
|
||||
bootstrapHubKubeConfigSecret = "bootstrap-hub-kubeconfig"
|
||||
hubKubeConfigSecret = "hub-kubeconfig"
|
||||
nucluesSpokeCoreNamespace = "open-cluster-management"
|
||||
spokeCoreApplied = "Applied"
|
||||
)
|
||||
|
||||
var (
|
||||
genericScheme = runtime.NewScheme()
|
||||
genericCodecs = serializer.NewCodecFactory(genericScheme)
|
||||
genericCodec = genericCodecs.UniversalDeserializer()
|
||||
)
|
||||
|
||||
type nucleusSpokeController struct {
|
||||
nucleusClient nucleusv1client.SpokeCoreInterface
|
||||
nucleusLister nucleuslister.SpokeCoreLister
|
||||
kubeClient kubernetes.Interface
|
||||
registrationGeneration int64
|
||||
workGeneration int64
|
||||
}
|
||||
|
||||
// NewNucleusAgentController construct nucleus agent controller
|
||||
func NewNucleusAgentController(
|
||||
func init() {
|
||||
utilruntime.Must(api.InstallKube(genericScheme))
|
||||
}
|
||||
|
||||
// NewNucleusSpokeController construct nucleus spoke controller
|
||||
func NewNucleusSpokeController(
|
||||
kubeClient kubernetes.Interface,
|
||||
nucleusClient nucleusv1client.SpokeCoreInterface,
|
||||
nucleusInformer nucleusinformer.SpokeCoreInformer,
|
||||
recorder events.Recorder) factory.Controller {
|
||||
controller := &nucleusAgentController{
|
||||
kubeClient: kubeClient,
|
||||
controller := &nucleusSpokeController{
|
||||
kubeClient: kubeClient,
|
||||
nucleusClient: nucleusClient,
|
||||
nucleusLister: nucleusInformer.Lister(),
|
||||
}
|
||||
|
||||
return factory.New().WithSync(controller.sync).ToController("NucleusHubController", recorder)
|
||||
return factory.New().WithSync(controller.sync).
|
||||
WithInformersQueueKeyFunc(func(obj runtime.Object) string {
|
||||
accessor, _ := meta.Accessor(obj)
|
||||
return accessor.GetName()
|
||||
}, nucleusInformer.Informer()).
|
||||
ToController("NucleusSpokeController", recorder)
|
||||
}
|
||||
|
||||
func (m *nucleusAgentController) sync(ctx context.Context, controllerContext factory.SyncContext) error {
|
||||
// spokeConfig is used to render the template of hub manifests
|
||||
type spokeConfig struct {
|
||||
SpokeCoreName string
|
||||
SpokeCoreNamespace string
|
||||
RegistrationImage string
|
||||
WorkImage string
|
||||
ClusterName string
|
||||
ExternalServerURL string
|
||||
HubKubeConfigSecret string
|
||||
BootStrapKubeConfigSecret string
|
||||
}
|
||||
|
||||
func (n *nucleusSpokeController) sync(ctx context.Context, controllerContext factory.SyncContext) error {
|
||||
spokeCoreName := controllerContext.QueueKey()
|
||||
klog.V(4).Infof("Reconciling SpokeCore %q", spokeCoreName)
|
||||
spokeCore, err := n.nucleusLister.Get(spokeCoreName)
|
||||
if errors.IsNotFound(err) {
|
||||
// AgentCore not found, could have been deleted, do nothing.
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
spokeCore = spokeCore.DeepCopy()
|
||||
|
||||
config := spokeConfig{
|
||||
SpokeCoreName: spokeCore.Name,
|
||||
SpokeCoreNamespace: spokeCore.Spec.Namespace,
|
||||
RegistrationImage: spokeCore.Spec.RegistrationImagePullSpec,
|
||||
WorkImage: spokeCore.Spec.WorkImagePullSpec,
|
||||
ClusterName: spokeCore.Spec.ClusterName,
|
||||
BootStrapKubeConfigSecret: bootstrapHubKubeConfigSecret,
|
||||
HubKubeConfigSecret: hubKubeConfigSecret,
|
||||
}
|
||||
// If namespace is not set, use the default namespace
|
||||
if config.SpokeCoreNamespace == "" {
|
||||
config.SpokeCoreNamespace = nucluesSpokeCoreNamespace
|
||||
}
|
||||
|
||||
// Update finalizer at first
|
||||
if spokeCore.DeletionTimestamp.IsZero() {
|
||||
hasFinalizer := false
|
||||
for i := range spokeCore.Finalizers {
|
||||
if spokeCore.Finalizers[i] == nucleusSpokeFinalizer {
|
||||
hasFinalizer = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasFinalizer {
|
||||
spokeCore.Finalizers = append(spokeCore.Finalizers, nucleusSpokeFinalizer)
|
||||
_, err := n.nucleusClient.Update(ctx, spokeCore, metav1.UpdateOptions{})
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// SpokeCore is deleting, we remove its related resources on spoke
|
||||
if !spokeCore.DeletionTimestamp.IsZero() {
|
||||
if err := n.cleanUp(ctx, controllerContext, config); err != nil {
|
||||
return err
|
||||
}
|
||||
return n.removeWorkFinalizer(ctx, spokeCore)
|
||||
}
|
||||
|
||||
// Start deploy spoke core components
|
||||
// Check if namespace exists
|
||||
_, err = n.kubeClient.CoreV1().Namespaces().Get(ctx, config.SpokeCoreNamespace, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
helpers.SetNucleusCondition(&spokeCore.Status.Conditions, nucleusapiv1.StatusCondition{
|
||||
Type: spokeCoreApplied,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: "SpokeCoreApplyFailed",
|
||||
Message: fmt.Sprintf("Failed to get namespace %q", config.SpokeCoreNamespace),
|
||||
})
|
||||
helpers.UpdateNucleusSpokeStatus(
|
||||
ctx, n.nucleusClient, spokeCoreName, helpers.UpdateNucleusSpokeConditionFn(spokeCore.Status.Conditions...))
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if bootstrap secret exists
|
||||
_, err = n.kubeClient.CoreV1().Secrets(config.SpokeCoreNamespace).Get(
|
||||
ctx, config.BootStrapKubeConfigSecret, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
helpers.SetNucleusCondition(&spokeCore.Status.Conditions, nucleusapiv1.StatusCondition{
|
||||
Type: spokeCoreApplied,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: "SpokeCoreApplyFailed",
|
||||
Message: fmt.Sprintf("Failed to get bootstracp secret %s/%s", config.SpokeCoreNamespace, config.BootStrapKubeConfigSecret),
|
||||
})
|
||||
helpers.UpdateNucleusSpokeStatus(
|
||||
ctx, n.nucleusClient, spokeCoreName, helpers.UpdateNucleusSpokeConditionFn(spokeCore.Status.Conditions...))
|
||||
return err
|
||||
}
|
||||
|
||||
// Deploy the static resources
|
||||
// Apply static files
|
||||
resourceResults := resourceapply.ApplyDirectly(
|
||||
resourceapply.NewKubeClientHolder(n.kubeClient),
|
||||
controllerContext.Recorder(),
|
||||
func(name string) ([]byte, error) {
|
||||
return assets.MustCreateAssetFromTemplate(name, bindata.MustAsset(filepath.Join("", name)), config).Data, nil
|
||||
},
|
||||
"manifests/spoke/spoke-clusterrolebinding.yaml",
|
||||
"manifests/spoke/spoke-serviceaccount.yaml",
|
||||
)
|
||||
errs := []error{}
|
||||
for _, result := range resourceResults {
|
||||
if result.Error != nil {
|
||||
errs = append(errs, fmt.Errorf("%q (%T): %v", result.File, result.Type, result.Error))
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
appleErros := operatorhelpers.NewMultiLineAggregate(errs)
|
||||
helpers.SetNucleusCondition(&spokeCore.Status.Conditions, nucleusapiv1.StatusCondition{
|
||||
Type: spokeCoreApplied,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: "SpokeCoreApplyFailed",
|
||||
Message: appleErros.Error(),
|
||||
})
|
||||
helpers.UpdateNucleusSpokeStatus(
|
||||
ctx, n.nucleusClient, spokeCoreName, helpers.UpdateNucleusSpokeConditionFn(spokeCore.Status.Conditions...))
|
||||
return appleErros
|
||||
}
|
||||
|
||||
// Create hub config secret
|
||||
hubSecret, err := n.kubeClient.CoreV1().Secrets(config.SpokeCoreNamespace).Get(
|
||||
ctx, hubKubeConfigSecret, metav1.GetOptions{})
|
||||
if errors.IsNotFound(err) {
|
||||
// Craete an empty secret with placeholder
|
||||
hubSecret = &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: hubKubeConfigSecret,
|
||||
Namespace: config.SpokeCoreNamespace,
|
||||
},
|
||||
Data: map[string][]byte{"placeholder": []byte("placeholder")},
|
||||
}
|
||||
hubSecret, err = n.kubeClient.CoreV1().Secrets(config.SpokeCoreNamespace).Create(ctx, hubSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
helpers.SetNucleusCondition(&spokeCore.Status.Conditions, nucleusapiv1.StatusCondition{
|
||||
Type: spokeCoreApplied,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: "SpokeCoreApplyFailed",
|
||||
Message: fmt.Sprintf("Failed to get hub kubeconfig secret with error %v", err),
|
||||
})
|
||||
helpers.UpdateNucleusSpokeStatus(
|
||||
ctx, n.nucleusClient, spokeCoreName, helpers.UpdateNucleusSpokeConditionFn(spokeCore.Status.Conditions...))
|
||||
return err
|
||||
}
|
||||
|
||||
// Deploy registration agent
|
||||
generation, err := n.applyDeployment(
|
||||
config, "manifests/spoke/spoke-registration-deployment.yaml", n.registrationGeneration, controllerContext)
|
||||
if err != nil {
|
||||
helpers.SetNucleusCondition(&spokeCore.Status.Conditions, nucleusapiv1.StatusCondition{
|
||||
Type: spokeCoreApplied,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: "SpokeCoreApplyFailed",
|
||||
Message: fmt.Sprintf("Failed to deploy registration deployment with error %v", err),
|
||||
})
|
||||
helpers.UpdateNucleusSpokeStatus(
|
||||
ctx, n.nucleusClient, spokeCoreName, helpers.UpdateNucleusSpokeConditionFn(spokeCore.Status.Conditions...))
|
||||
return err
|
||||
}
|
||||
n.registrationGeneration = generation
|
||||
|
||||
// If cluster name is empty, read cluster name from hub config secret
|
||||
if config.ClusterName == "" {
|
||||
clusterName := hubSecret.Data["cluster-name"]
|
||||
if clusterName == nil {
|
||||
helpers.SetNucleusCondition(&spokeCore.Status.Conditions, nucleusapiv1.StatusCondition{
|
||||
Type: spokeCoreApplied,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: "SpokeCoreApplyFailed",
|
||||
Message: fmt.Sprintf("Failed to get cluster name"),
|
||||
})
|
||||
helpers.UpdateNucleusSpokeStatus(
|
||||
ctx, n.nucleusClient, spokeCoreName, helpers.UpdateNucleusSpokeConditionFn(spokeCore.Status.Conditions...))
|
||||
return fmt.Errorf("Failed to get cluster name")
|
||||
}
|
||||
config.ClusterName = string(clusterName)
|
||||
}
|
||||
|
||||
// If hub kubeconfig does not exist, return err.
|
||||
if hubSecret.Data["kubeconfig"] == nil {
|
||||
klog.Infof("data is %#v", hubSecret.Data)
|
||||
return fmt.Errorf("Failed to get kubeconfig from hub kubeconfig secret")
|
||||
}
|
||||
|
||||
// Deploy work agent
|
||||
generation, err = n.applyDeployment(
|
||||
config, "manifests/spoke/spoke-work-deployment.yaml", n.workGeneration, controllerContext)
|
||||
if err != nil {
|
||||
helpers.SetNucleusCondition(&spokeCore.Status.Conditions, nucleusapiv1.StatusCondition{
|
||||
Type: spokeCoreApplied,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: "SpokeCoreApplyFailed",
|
||||
Message: fmt.Sprintf("Failed to deploy work deployment with error %v", err),
|
||||
})
|
||||
helpers.UpdateNucleusSpokeStatus(
|
||||
ctx, n.nucleusClient, spokeCoreName, helpers.UpdateNucleusSpokeConditionFn(spokeCore.Status.Conditions...))
|
||||
return err
|
||||
}
|
||||
n.workGeneration = generation
|
||||
|
||||
// Update status
|
||||
helpers.SetNucleusCondition(&spokeCore.Status.Conditions, nucleusapiv1.StatusCondition{
|
||||
Type: spokeCoreApplied,
|
||||
Status: metav1.ConditionTrue,
|
||||
Reason: "SpokeCoreApplied",
|
||||
Message: "Spoke Core Component Applied",
|
||||
})
|
||||
helpers.UpdateNucleusSpokeStatus(
|
||||
ctx, n.nucleusClient, spokeCoreName, helpers.UpdateNucleusSpokeConditionFn(spokeCore.Status.Conditions...))
|
||||
return err
|
||||
}
|
||||
|
||||
func (n *nucleusSpokeController) applyDeployment(
|
||||
config spokeConfig, file string, generation int64, controllerContext factory.SyncContext) (int64, error) {
|
||||
deploymentRaw := assets.MustCreateAssetFromTemplate(
|
||||
file,
|
||||
bindata.MustAsset(filepath.Join("", file)), config).Data
|
||||
deployment, _, err := genericCodec.Decode(deploymentRaw, nil, nil)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("%q: %v", file, err)
|
||||
}
|
||||
updatedDeployment, updated, err := resourceapply.ApplyDeployment(
|
||||
n.kubeClient.AppsV1(),
|
||||
controllerContext.Recorder(),
|
||||
deployment.(*appsv1.Deployment), generation, false)
|
||||
if err != nil {
|
||||
klog.Errorf("Failed to apply hub deployment manifest: %v", err)
|
||||
return 0, fmt.Errorf("%q (%T): %v", file, deployment, err)
|
||||
}
|
||||
|
||||
// Record the generation, so the deployment is only updated when generation is changed.
|
||||
if updated {
|
||||
generation = updatedDeployment.ObjectMeta.Generation
|
||||
}
|
||||
|
||||
return generation, nil
|
||||
}
|
||||
|
||||
func (n *nucleusSpokeController) cleanUp(ctx context.Context, controllerContext factory.SyncContext, config spokeConfig) error {
|
||||
// Remove deployment
|
||||
registrationDeployment := fmt.Sprintf("%s-registration-agent", config.SpokeCoreName)
|
||||
err := n.kubeClient.AppsV1().Deployments(config.SpokeCoreNamespace).Delete(ctx, registrationDeployment, metav1.DeleteOptions{})
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
controllerContext.Recorder().Eventf("DeploymentDeleted", "deployment %s is deleted", registrationDeployment)
|
||||
workDeployment := fmt.Sprintf("%s-work-agent", config.SpokeCoreName)
|
||||
err = n.kubeClient.AppsV1().Deployments(config.SpokeCoreNamespace).Delete(ctx, workDeployment, metav1.DeleteOptions{})
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
// Remove secret
|
||||
err = n.kubeClient.CoreV1().Secrets(config.SpokeCoreNamespace).Delete(ctx, config.HubKubeConfigSecret, metav1.DeleteOptions{})
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
controllerContext.Recorder().Eventf("SecretDeleted", "secret %s is deleted", config.HubKubeConfigSecret)
|
||||
// Remove service account
|
||||
serviceAccountName := fmt.Sprintf("%s-sa", config.SpokeCoreName)
|
||||
err = n.kubeClient.CoreV1().ServiceAccounts(config.SpokeCoreNamespace).Delete(ctx, serviceAccountName, metav1.DeleteOptions{})
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
controllerContext.Recorder().Eventf("ServiceAccountDeleted", "serviceaccoount %s is deleted", serviceAccountName)
|
||||
// Remove clusterrolebinding
|
||||
clusterRoleBindingName := fmt.Sprintf("system:open-cluster-management:%s", config.SpokeCoreName)
|
||||
err = n.kubeClient.RbacV1().ClusterRoleBindings().Delete(ctx, clusterRoleBindingName, metav1.DeleteOptions{})
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
controllerContext.Recorder().Eventf("ClusterRoleBindingDeleted", "clusterrole %s is deleted", clusterRoleBindingName)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *nucleusSpokeController) removeWorkFinalizer(ctx context.Context, deploy *nucleusapiv1.SpokeCore) error {
|
||||
copiedFinalizers := []string{}
|
||||
for i := range deploy.Finalizers {
|
||||
if deploy.Finalizers[i] == nucleusSpokeFinalizer {
|
||||
continue
|
||||
}
|
||||
copiedFinalizers = append(copiedFinalizers, deploy.Finalizers[i])
|
||||
}
|
||||
|
||||
if len(deploy.Finalizers) != len(copiedFinalizers) {
|
||||
deploy.Finalizers = copiedFinalizers
|
||||
_, err := n.nucleusClient.Update(ctx, deploy, metav1.UpdateOptions{})
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func readClusterNameFromSecret(secret *corev1.Secret) (string, error) {
|
||||
if secret.Data["cluster-name"] == nil {
|
||||
return "", fmt.Errorf("Unable to find cluster name in secret")
|
||||
}
|
||||
|
||||
return string(secret.Data["cluster-name"]), nil
|
||||
}
|
||||
|
||||
func readKubuConfigFromSecret(secret *corev1.Secret, config spokeConfig) (string, error) {
|
||||
if secret.Data["cluster-name"] == nil {
|
||||
return "", fmt.Errorf("Unable to find cluster name in secret")
|
||||
}
|
||||
|
||||
return string(secret.Data["cluster-name"]), nil
|
||||
}
|
||||
|
||||
279
pkg/operators/spoke/controller_test.go
Normal file
279
pkg/operators/spoke/controller_test.go
Normal file
@@ -0,0 +1,279 @@
|
||||
package spoke
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
fakenucleusclient "github.com/open-cluster-management/api/client/nucleus/clientset/versioned/fake"
|
||||
nucleusinformers "github.com/open-cluster-management/api/client/nucleus/informers/externalversions"
|
||||
nucleusapiv1 "github.com/open-cluster-management/api/nucleus/v1"
|
||||
"github.com/openshift/library-go/pkg/operator/events"
|
||||
"github.com/openshift/library-go/pkg/operator/events/eventstesting"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
fakekube "k8s.io/client-go/kubernetes/fake"
|
||||
clienttesting "k8s.io/client-go/testing"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
)
|
||||
|
||||
type testController struct {
|
||||
controller *nucleusSpokeController
|
||||
kubeClient *fakekube.Clientset
|
||||
nucleusClient *fakenucleusclient.Clientset
|
||||
}
|
||||
|
||||
type fakeSyncContext struct {
|
||||
key string
|
||||
queue workqueue.RateLimitingInterface
|
||||
recorder events.Recorder
|
||||
}
|
||||
|
||||
func (f fakeSyncContext) Queue() workqueue.RateLimitingInterface { return f.queue }
|
||||
func (f fakeSyncContext) QueueKey() string { return f.key }
|
||||
func (f fakeSyncContext) Recorder() events.Recorder { return f.recorder }
|
||||
|
||||
func newFakeSyncContext(t *testing.T, key string) *fakeSyncContext {
|
||||
return &fakeSyncContext{
|
||||
key: key,
|
||||
queue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()),
|
||||
recorder: eventstesting.NewTestingEventRecorder(t),
|
||||
}
|
||||
}
|
||||
|
||||
func newSpokeCore(name, namespace, clustername string) *nucleusapiv1.SpokeCore {
|
||||
return &nucleusapiv1.SpokeCore{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Finalizers: []string{nucleusSpokeFinalizer},
|
||||
},
|
||||
Spec: nucleusapiv1.SpokeCoreSpec{
|
||||
RegistrationImagePullSpec: "testregistration",
|
||||
WorkImagePullSpec: "testwork",
|
||||
ClusterName: clustername,
|
||||
Namespace: namespace,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newSecret(name, namespace string) *corev1.Secret {
|
||||
return &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Data: map[string][]byte{},
|
||||
}
|
||||
}
|
||||
|
||||
func newNamespace(name string) *corev1.Namespace {
|
||||
return &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newTestController(spokecore *nucleusapiv1.SpokeCore, objects ...runtime.Object) *testController {
|
||||
fakeKubeClient := fakekube.NewSimpleClientset(objects...)
|
||||
fakeNucleusClient := fakenucleusclient.NewSimpleClientset(spokecore)
|
||||
nucleusInformers := nucleusinformers.NewSharedInformerFactory(fakeNucleusClient, 5*time.Minute)
|
||||
|
||||
hubController := &nucleusSpokeController{
|
||||
nucleusClient: fakeNucleusClient.NucleusV1().SpokeCores(),
|
||||
kubeClient: fakeKubeClient,
|
||||
nucleusLister: nucleusInformers.Nucleus().V1().SpokeCores().Lister(),
|
||||
}
|
||||
|
||||
store := nucleusInformers.Nucleus().V1().SpokeCores().Informer().GetStore()
|
||||
store.Add(spokecore)
|
||||
|
||||
return &testController{
|
||||
controller: hubController,
|
||||
kubeClient: fakeKubeClient,
|
||||
nucleusClient: fakeNucleusClient,
|
||||
}
|
||||
}
|
||||
|
||||
func assertAction(t *testing.T, actual clienttesting.Action, expected string) {
|
||||
if actual.GetVerb() != expected {
|
||||
t.Errorf("expected %s action but got: %#v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func assertCondition(t *testing.T, actual runtime.Object, expectedCondition string, expectedStatus metav1.ConditionStatus) {
|
||||
spokeCore := actual.(*nucleusapiv1.SpokeCore)
|
||||
conditions := spokeCore.Status.Conditions
|
||||
if len(conditions) != 1 {
|
||||
t.Errorf("expected 1 condition but got: %#v", conditions)
|
||||
}
|
||||
condition := conditions[0]
|
||||
if condition.Type != expectedCondition {
|
||||
t.Errorf("expected %s but got: %s", expectedCondition, condition.Type)
|
||||
}
|
||||
if condition.Status != expectedStatus {
|
||||
t.Errorf("expected %s but got: %s", expectedStatus, condition.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func ensureNameNamespace(t *testing.T, actualName, actualNamespace, name, namespace string) {
|
||||
if actualName != name {
|
||||
t.Errorf("Name of the object does not match, expected %s, actual %s", name, actualName)
|
||||
}
|
||||
|
||||
if actualNamespace != namespace {
|
||||
t.Errorf("Namespace of the object does not match, expected %s, actual %s", namespace, actualNamespace)
|
||||
}
|
||||
}
|
||||
|
||||
func ensureObject(t *testing.T, object runtime.Object, spokeCore *nucleusapiv1.SpokeCore) {
|
||||
access, err := meta.Accessor(object)
|
||||
if err != nil {
|
||||
t.Errorf("Unable to access objectmeta: %v", err)
|
||||
}
|
||||
|
||||
switch o := object.(type) {
|
||||
case *corev1.ServiceAccount:
|
||||
ensureNameNamespace(t, access.GetName(), access.GetNamespace(), fmt.Sprintf("%s-sa", spokeCore.Name), spokeCore.Spec.Namespace)
|
||||
case *appsv1.Deployment:
|
||||
if strings.Contains(access.GetName(), "registration") {
|
||||
ensureNameNamespace(
|
||||
t, access.GetName(), access.GetNamespace(),
|
||||
fmt.Sprintf("%s-registration-agent", spokeCore.Name), spokeCore.Spec.Namespace)
|
||||
if spokeCore.Spec.RegistrationImagePullSpec != o.Spec.Template.Spec.Containers[0].Image {
|
||||
t.Errorf("Image does not match to the expected.")
|
||||
}
|
||||
} else if strings.Contains(access.GetName(), "work") {
|
||||
ensureNameNamespace(
|
||||
t, access.GetName(), access.GetNamespace(),
|
||||
fmt.Sprintf("%s-work-agent", spokeCore.Name), spokeCore.Spec.Namespace)
|
||||
if spokeCore.Spec.WorkImagePullSpec != o.Spec.Template.Spec.Containers[0].Image {
|
||||
t.Errorf("Image does not match to the expected.")
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Unexpected deployment")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestSyncDeploy test deployment of spoke components
|
||||
func TestSyncDeploy(t *testing.T) {
|
||||
spokeCore := newSpokeCore("testspoke", "testns", "cluster1")
|
||||
bootStrapSecret := newSecret(bootstrapHubKubeConfigSecret, "testns")
|
||||
hubKubeConfigSecret := newSecret(hubKubeConfigSecret, "testns")
|
||||
hubKubeConfigSecret.Data["kubeconfig"] = []byte("dummuykubeconnfig")
|
||||
namespace := newNamespace("testns")
|
||||
controller := newTestController(spokeCore, bootStrapSecret, hubKubeConfigSecret, namespace)
|
||||
syncContext := newFakeSyncContext(t, "testspoke")
|
||||
|
||||
err := controller.controller.sync(nil, syncContext)
|
||||
if err != nil {
|
||||
t.Errorf("Expected non error when sync, %v", err)
|
||||
}
|
||||
|
||||
createObjects := []runtime.Object{}
|
||||
kubeActions := controller.kubeClient.Actions()
|
||||
for _, action := range kubeActions {
|
||||
if action.GetVerb() == "create" {
|
||||
object := action.(clienttesting.CreateActionImpl).Object
|
||||
createObjects = append(createObjects, object)
|
||||
}
|
||||
}
|
||||
|
||||
// Check if resources are created as expected
|
||||
if len(createObjects) != 4 {
|
||||
t.Errorf("Expect 4 objects created in the sync loop, actual %d", len(createObjects))
|
||||
}
|
||||
for _, object := range createObjects {
|
||||
ensureObject(t, object, spokeCore)
|
||||
}
|
||||
|
||||
nucleusAction := controller.nucleusClient.Actions()
|
||||
if len(nucleusAction) != 2 {
|
||||
t.Errorf("Expect 2 actions in the sync loop, actual %#v", nucleusAction)
|
||||
}
|
||||
|
||||
assertAction(t, nucleusAction[1], "update")
|
||||
assertCondition(t, nucleusAction[1].(clienttesting.UpdateActionImpl).Object, spokeCoreApplied, metav1.ConditionTrue)
|
||||
}
|
||||
|
||||
// TestSyncWithNoSecret test the scenario that bootstrap secret and hub config secret does not exist
|
||||
func TestSyncWithNoSecret(t *testing.T) {
|
||||
spokeCore := newSpokeCore("testspoke", "testns", "")
|
||||
bootStrapSecret := newSecret(bootstrapHubKubeConfigSecret, "testns")
|
||||
hubSecret := newSecret(hubKubeConfigSecret, "testns")
|
||||
namespace := newNamespace("testns")
|
||||
controller := newTestController(spokeCore, namespace)
|
||||
syncContext := newFakeSyncContext(t, "testspoke")
|
||||
|
||||
// Return err since bootstrap secret does not exist
|
||||
err := controller.controller.sync(nil, syncContext)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error when sync")
|
||||
}
|
||||
nucleusAction := controller.nucleusClient.Actions()
|
||||
if len(nucleusAction) != 2 {
|
||||
t.Errorf("Expect 2 actions in the sync loop, actual %#v", nucleusAction)
|
||||
}
|
||||
|
||||
assertAction(t, nucleusAction[1], "update")
|
||||
assertCondition(t, nucleusAction[1].(clienttesting.UpdateActionImpl).Object, spokeCoreApplied, metav1.ConditionFalse)
|
||||
|
||||
// Add bootstrap secret and sync again
|
||||
controller.kubeClient.PrependReactor("get", "secrets", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
if action.GetVerb() != "get" {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
getAction := action.(clienttesting.GetActionImpl)
|
||||
if getAction.Name != bootstrapHubKubeConfigSecret {
|
||||
return false, nil, errors.NewNotFound(
|
||||
corev1.Resource("secrets"), bootstrapHubKubeConfigSecret)
|
||||
}
|
||||
return true, bootStrapSecret, nil
|
||||
})
|
||||
// Return err since cluster-name cannot be found in hubkubeconfig secret
|
||||
err = controller.controller.sync(nil, syncContext)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error when sync")
|
||||
}
|
||||
nucleusAction = controller.nucleusClient.Actions()
|
||||
if len(nucleusAction) != 4 {
|
||||
t.Errorf("Expect 4 actions in the sync loop, actual %#v", nucleusAction)
|
||||
}
|
||||
|
||||
assertAction(t, nucleusAction[3], "update")
|
||||
assertCondition(t, nucleusAction[3].(clienttesting.UpdateActionImpl).Object, spokeCoreApplied, metav1.ConditionFalse)
|
||||
|
||||
// Add hub config secret and sync again
|
||||
hubSecret.Data["kubeconfig"] = []byte("dummykubeconfig")
|
||||
hubSecret.Data["cluster-name"] = []byte("cluster1")
|
||||
controller.kubeClient.PrependReactor("get", "secrets", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
if action.GetVerb() != "get" {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
getAction := action.(clienttesting.GetActionImpl)
|
||||
if getAction.Name != hubKubeConfigSecret {
|
||||
return false, nil, errors.NewNotFound(
|
||||
corev1.Resource("secrets"), hubKubeConfigSecret)
|
||||
}
|
||||
return true, hubSecret, nil
|
||||
})
|
||||
err = controller.controller.sync(nil, syncContext)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error when sync: %v", err)
|
||||
}
|
||||
nucleusAction = controller.nucleusClient.Actions()
|
||||
if len(nucleusAction) != 6 {
|
||||
t.Errorf("Expect 6 actions in the sync loop, actual %#v", nucleusAction)
|
||||
}
|
||||
|
||||
assertAction(t, nucleusAction[5], "update")
|
||||
assertCondition(t, nucleusAction[5].(clienttesting.UpdateActionImpl).Object, spokeCoreApplied, metav1.ConditionTrue)
|
||||
}
|
||||
@@ -50,7 +50,11 @@ spec:
|
||||
to be deployed on the spoke cluster.
|
||||
type: array
|
||||
items:
|
||||
description: Manifest represents a resource to be deployed on
|
||||
spoke cluster
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
x-kubernetes-embedded-resource: true
|
||||
status:
|
||||
description: Status represents the current status of work
|
||||
type: object
|
||||
333
vendor/github.com/open-cluster-management/api/work/v1/generated.pb.go
generated
vendored
333
vendor/github.com/open-cluster-management/api/work/v1/generated.pb.go
generated
vendored
@@ -10,7 +10,6 @@ import (
|
||||
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
k8s_io_apimachinery_pkg_apis_meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
math "math"
|
||||
math_bits "math/bits"
|
||||
@@ -29,10 +28,38 @@ var _ = math.Inf
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
func (m *Manifest) Reset() { *m = Manifest{} }
|
||||
func (*Manifest) ProtoMessage() {}
|
||||
func (*Manifest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_97234883da270a20, []int{0}
|
||||
}
|
||||
func (m *Manifest) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *Manifest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
func (m *Manifest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Manifest.Merge(m, src)
|
||||
}
|
||||
func (m *Manifest) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *Manifest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Manifest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Manifest proto.InternalMessageInfo
|
||||
|
||||
func (m *ManifestCondition) Reset() { *m = ManifestCondition{} }
|
||||
func (*ManifestCondition) ProtoMessage() {}
|
||||
func (*ManifestCondition) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_97234883da270a20, []int{0}
|
||||
return fileDescriptor_97234883da270a20, []int{1}
|
||||
}
|
||||
func (m *ManifestCondition) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -60,7 +87,7 @@ var xxx_messageInfo_ManifestCondition proto.InternalMessageInfo
|
||||
func (m *ManifestResourceMeta) Reset() { *m = ManifestResourceMeta{} }
|
||||
func (*ManifestResourceMeta) ProtoMessage() {}
|
||||
func (*ManifestResourceMeta) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_97234883da270a20, []int{1}
|
||||
return fileDescriptor_97234883da270a20, []int{2}
|
||||
}
|
||||
func (m *ManifestResourceMeta) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -88,7 +115,7 @@ var xxx_messageInfo_ManifestResourceMeta proto.InternalMessageInfo
|
||||
func (m *ManifestResourceStatus) Reset() { *m = ManifestResourceStatus{} }
|
||||
func (*ManifestResourceStatus) ProtoMessage() {}
|
||||
func (*ManifestResourceStatus) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_97234883da270a20, []int{2}
|
||||
return fileDescriptor_97234883da270a20, []int{3}
|
||||
}
|
||||
func (m *ManifestResourceStatus) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -116,7 +143,7 @@ var xxx_messageInfo_ManifestResourceStatus proto.InternalMessageInfo
|
||||
func (m *ManifestWork) Reset() { *m = ManifestWork{} }
|
||||
func (*ManifestWork) ProtoMessage() {}
|
||||
func (*ManifestWork) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_97234883da270a20, []int{3}
|
||||
return fileDescriptor_97234883da270a20, []int{4}
|
||||
}
|
||||
func (m *ManifestWork) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -144,7 +171,7 @@ var xxx_messageInfo_ManifestWork proto.InternalMessageInfo
|
||||
func (m *ManifestWorkList) Reset() { *m = ManifestWorkList{} }
|
||||
func (*ManifestWorkList) ProtoMessage() {}
|
||||
func (*ManifestWorkList) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_97234883da270a20, []int{4}
|
||||
return fileDescriptor_97234883da270a20, []int{5}
|
||||
}
|
||||
func (m *ManifestWorkList) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -172,7 +199,7 @@ var xxx_messageInfo_ManifestWorkList proto.InternalMessageInfo
|
||||
func (m *ManifestWorkSpec) Reset() { *m = ManifestWorkSpec{} }
|
||||
func (*ManifestWorkSpec) ProtoMessage() {}
|
||||
func (*ManifestWorkSpec) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_97234883da270a20, []int{5}
|
||||
return fileDescriptor_97234883da270a20, []int{6}
|
||||
}
|
||||
func (m *ManifestWorkSpec) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -200,7 +227,7 @@ var xxx_messageInfo_ManifestWorkSpec proto.InternalMessageInfo
|
||||
func (m *ManifestWorkStatus) Reset() { *m = ManifestWorkStatus{} }
|
||||
func (*ManifestWorkStatus) ProtoMessage() {}
|
||||
func (*ManifestWorkStatus) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_97234883da270a20, []int{6}
|
||||
return fileDescriptor_97234883da270a20, []int{7}
|
||||
}
|
||||
func (m *ManifestWorkStatus) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -228,7 +255,7 @@ var xxx_messageInfo_ManifestWorkStatus proto.InternalMessageInfo
|
||||
func (m *ManifestsTemplate) Reset() { *m = ManifestsTemplate{} }
|
||||
func (*ManifestsTemplate) ProtoMessage() {}
|
||||
func (*ManifestsTemplate) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_97234883da270a20, []int{7}
|
||||
return fileDescriptor_97234883da270a20, []int{8}
|
||||
}
|
||||
func (m *ManifestsTemplate) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -256,7 +283,7 @@ var xxx_messageInfo_ManifestsTemplate proto.InternalMessageInfo
|
||||
func (m *StatusCondition) Reset() { *m = StatusCondition{} }
|
||||
func (*StatusCondition) ProtoMessage() {}
|
||||
func (*StatusCondition) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_97234883da270a20, []int{8}
|
||||
return fileDescriptor_97234883da270a20, []int{9}
|
||||
}
|
||||
func (m *StatusCondition) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -282,6 +309,7 @@ func (m *StatusCondition) XXX_DiscardUnknown() {
|
||||
var xxx_messageInfo_StatusCondition proto.InternalMessageInfo
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Manifest)(nil), "github.com.open_cluster_management.api.work.v1.Manifest")
|
||||
proto.RegisterType((*ManifestCondition)(nil), "github.com.open_cluster_management.api.work.v1.ManifestCondition")
|
||||
proto.RegisterType((*ManifestResourceMeta)(nil), "github.com.open_cluster_management.api.work.v1.ManifestResourceMeta")
|
||||
proto.RegisterType((*ManifestResourceStatus)(nil), "github.com.open_cluster_management.api.work.v1.ManifestResourceStatus")
|
||||
@@ -298,63 +326,97 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptor_97234883da270a20 = []byte{
|
||||
// 884 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0xcb, 0x8b, 0x1c, 0x45,
|
||||
0x18, 0x9f, 0xee, 0xec, 0xec, 0xa3, 0x76, 0xdd, 0x24, 0x45, 0x08, 0xcd, 0x1e, 0x7a, 0x97, 0x16,
|
||||
0x64, 0x15, 0xb7, 0xda, 0x5d, 0x44, 0x3c, 0x88, 0x8f, 0x56, 0x23, 0x62, 0x36, 0x81, 0xca, 0x62,
|
||||
0x40, 0x24, 0xb1, 0xb6, 0xa7, 0xd2, 0x5b, 0x99, 0xe9, 0xaa, 0xa6, 0xaa, 0x66, 0xe2, 0x5e, 0x44,
|
||||
0x10, 0xc4, 0x83, 0x07, 0xf1, 0x6f, 0xf1, 0x0f, 0xf0, 0xb8, 0xc7, 0x80, 0x97, 0x9c, 0x06, 0x77,
|
||||
0xfc, 0x2f, 0x3c, 0x49, 0x55, 0x57, 0x3f, 0x66, 0x66, 0x43, 0xf6, 0x01, 0x9e, 0x66, 0xfa, 0x7b,
|
||||
0xfc, 0x7e, 0xdf, 0xf7, 0xd5, 0xf7, 0x00, 0x1f, 0x66, 0x4c, 0x1f, 0x0d, 0x0f, 0x51, 0x2a, 0xf2,
|
||||
0x58, 0x14, 0x94, 0xef, 0xa4, 0x83, 0xa1, 0xd2, 0x54, 0xee, 0xe4, 0x84, 0x93, 0x8c, 0xe6, 0x94,
|
||||
0xeb, 0x98, 0x14, 0x2c, 0x7e, 0x26, 0x64, 0x3f, 0x1e, 0xed, 0xc6, 0x19, 0xe5, 0x54, 0x12, 0x4d,
|
||||
0x7b, 0xa8, 0x90, 0x42, 0x0b, 0x88, 0x1a, 0x7f, 0x64, 0xfc, 0x1f, 0x3b, 0xff, 0xc7, 0x8d, 0x3f,
|
||||
0x22, 0x05, 0x43, 0xc6, 0x1f, 0x8d, 0x76, 0x37, 0x76, 0x5a, 0x7c, 0x99, 0xc8, 0x44, 0x6c, 0x61,
|
||||
0x0e, 0x87, 0x4f, 0xec, 0x97, 0xfd, 0xb0, 0xff, 0x4a, 0xf8, 0x8d, 0x77, 0xfb, 0xef, 0x2b, 0xc4,
|
||||
0x84, 0x09, 0x21, 0x27, 0xe9, 0x11, 0xe3, 0x54, 0x1e, 0xc7, 0x45, 0x3f, 0x33, 0x02, 0x15, 0xe7,
|
||||
0x54, 0x93, 0x33, 0x82, 0xda, 0x88, 0x5f, 0xe6, 0x25, 0x87, 0x5c, 0xb3, 0x9c, 0xce, 0x39, 0xbc,
|
||||
0xf7, 0x2a, 0x07, 0x95, 0x1e, 0xd1, 0x9c, 0xcc, 0xfa, 0x45, 0xbf, 0xf8, 0xe0, 0xe6, 0x3e, 0xe1,
|
||||
0xec, 0x09, 0x55, 0xfa, 0x53, 0xc1, 0x7b, 0x4c, 0x33, 0xc1, 0xe1, 0x0f, 0x60, 0x4d, 0x52, 0x25,
|
||||
0x86, 0x32, 0xa5, 0xfb, 0x54, 0x93, 0xc0, 0xdb, 0xf2, 0xb6, 0x57, 0xf7, 0x3e, 0xbb, 0x60, 0xa9,
|
||||
0x50, 0x05, 0x8c, 0x5b, 0x58, 0xc9, 0xad, 0x93, 0xf1, 0x66, 0x67, 0x32, 0xde, 0x5c, 0x6b, 0x4b,
|
||||
0xf1, 0x14, 0x1f, 0x54, 0x00, 0xa4, 0x55, 0x30, 0x2a, 0xf0, 0xb7, 0xae, 0x6d, 0xaf, 0xee, 0x7d,
|
||||
0x74, 0x51, 0xf6, 0x07, 0x9a, 0xe8, 0xa1, 0xaa, 0x93, 0x4a, 0xa0, 0x23, 0x06, 0xb5, 0x48, 0xe1,
|
||||
0x16, 0x4d, 0xf4, 0x87, 0x0f, 0x6e, 0x9d, 0x15, 0x31, 0x7c, 0x13, 0x2c, 0x09, 0xd9, 0x63, 0x9c,
|
||||
0x0c, 0x6c, 0x21, 0xba, 0xc9, 0x75, 0x87, 0xb4, 0x74, 0xbf, 0x14, 0xe3, 0x4a, 0x0f, 0x5f, 0x07,
|
||||
0xdd, 0x4c, 0x8a, 0x61, 0x11, 0xf8, 0x5b, 0xde, 0xf6, 0x4a, 0xf2, 0x9a, 0x33, 0xec, 0x7e, 0x61,
|
||||
0x84, 0xb8, 0xd4, 0x19, 0xbc, 0x11, 0x95, 0x8a, 0x09, 0x1e, 0x5c, 0xb3, 0x66, 0x35, 0xde, 0xd7,
|
||||
0xa5, 0x18, 0x57, 0x7a, 0xb8, 0x05, 0x16, 0xfa, 0x8c, 0xf7, 0x82, 0x05, 0x6b, 0xb7, 0xe6, 0xec,
|
||||
0x16, 0xbe, 0x62, 0xbc, 0x87, 0xad, 0x06, 0xbe, 0x0d, 0x96, 0xab, 0xd2, 0x05, 0x5d, 0x6b, 0x75,
|
||||
0xc3, 0x59, 0x2d, 0x57, 0x49, 0xe0, 0xda, 0xc2, 0xe0, 0x71, 0x92, 0xd3, 0x60, 0x71, 0x1a, 0xef,
|
||||
0x1e, 0xc9, 0x29, 0xb6, 0x1a, 0x18, 0x83, 0x15, 0xf3, 0xab, 0x0a, 0x92, 0xd2, 0x60, 0xc9, 0x9a,
|
||||
0xdd, 0x74, 0x66, 0x2b, 0xf7, 0x2a, 0x05, 0x6e, 0x6c, 0xa2, 0x5f, 0x3d, 0x70, 0x7b, 0xb6, 0x6c,
|
||||
0x65, 0xe9, 0xa1, 0x04, 0x2b, 0xb9, 0xd3, 0x54, 0xaf, 0xf8, 0xc9, 0x65, 0x7b, 0xa8, 0x79, 0xc7,
|
||||
0x3a, 0x9c, 0x4a, 0xa5, 0x70, 0x43, 0x13, 0xfd, 0xe9, 0x83, 0xb5, 0x4a, 0xf1, 0x50, 0xc8, 0x3e,
|
||||
0xfc, 0x0e, 0x2c, 0x9b, 0x29, 0xeb, 0x91, 0xba, 0x8f, 0xdf, 0x41, 0xe5, 0xb0, 0xa0, 0xf6, 0xb0,
|
||||
0xa0, 0xa2, 0x9f, 0x19, 0x81, 0x42, 0xc6, 0xda, 0x30, 0xdf, 0x3f, 0x7c, 0x4a, 0x53, 0x6d, 0x7b,
|
||||
0xb6, 0x6e, 0x9d, 0x46, 0x86, 0x6b, 0x54, 0x78, 0x08, 0x16, 0x54, 0x41, 0x53, 0xfb, 0xe6, 0xab,
|
||||
0x7b, 0x1f, 0x5f, 0x36, 0x43, 0x13, 0xed, 0x83, 0x82, 0xa6, 0xcd, 0xb3, 0x98, 0x2f, 0x6c, 0xb1,
|
||||
0xe1, 0x53, 0xb0, 0xa8, 0x6c, 0x51, 0x6d, 0xcb, 0xac, 0xee, 0x25, 0x57, 0x62, 0xb1, 0x48, 0xc9,
|
||||
0xba, 0xe3, 0x59, 0x2c, 0xbf, 0xb1, 0x63, 0x88, 0xfe, 0xf2, 0xc0, 0x8d, 0xb6, 0xf9, 0x5d, 0xa6,
|
||||
0x34, 0xfc, 0x76, 0xae, 0x8c, 0xe8, 0x7c, 0x65, 0x34, 0xde, 0xb6, 0x88, 0x75, 0x5f, 0x56, 0x92,
|
||||
0x56, 0x09, 0x09, 0xe8, 0x32, 0x4d, 0xf3, 0xaa, 0x4b, 0x3e, 0xb8, 0x4a, 0x76, 0xcd, 0xd4, 0x7d,
|
||||
0x69, 0x20, 0x71, 0x89, 0x1c, 0xfd, 0x34, 0x93, 0x95, 0x29, 0x2e, 0x14, 0x60, 0xd9, 0x40, 0x0c,
|
||||
0x04, 0xe9, 0xb9, 0xac, 0x2e, 0xdd, 0xa0, 0xea, 0x80, 0xe6, 0xc5, 0x80, 0x68, 0xda, 0x24, 0xfa,
|
||||
0xd0, 0x41, 0xe3, 0x9a, 0x24, 0xfa, 0xdd, 0x07, 0x70, 0xfe, 0x29, 0x66, 0x16, 0x9e, 0xf7, 0xbf,
|
||||
0x2c, 0x3c, 0xf8, 0xb3, 0x07, 0xd6, 0xe5, 0xd4, 0xc4, 0xba, 0x16, 0xbe, 0x73, 0xd5, 0x45, 0xef,
|
||||
0x1a, 0xec, 0xb6, 0x0b, 0x60, 0x7d, 0x5a, 0x8e, 0x67, 0x58, 0x23, 0xd5, 0xdc, 0xa0, 0xba, 0x8a,
|
||||
0xf0, 0xd1, 0xfc, 0xf2, 0xd8, 0x79, 0x69, 0xc7, 0xb9, 0x2b, 0x87, 0x30, 0x79, 0xf6, 0xf9, 0xf7,
|
||||
0x9a, 0x72, 0xf5, 0xea, 0x45, 0x31, 0xf6, 0xc1, 0xf5, 0x99, 0x8a, 0x99, 0xf5, 0xa8, 0x8f, 0x0b,
|
||||
0x6a, 0x5b, 0xa1, 0xb5, 0x1e, 0x0f, 0x8e, 0x0b, 0x8a, 0xad, 0x06, 0x3e, 0xaa, 0xe7, 0xb0, 0xdc,
|
||||
0xf0, 0x77, 0xa6, 0x67, 0xe8, 0xdf, 0xf1, 0xe6, 0xb9, 0x0e, 0x3e, 0xaa, 0x39, 0xa7, 0x67, 0x0f,
|
||||
0x8e, 0x00, 0x1c, 0x10, 0xa5, 0x0f, 0x24, 0xe1, 0xca, 0xea, 0x0f, 0x58, 0x4e, 0xdd, 0xcc, 0xbf,
|
||||
0x75, 0xbe, 0x81, 0x33, 0x1e, 0xc9, 0x86, 0x8b, 0x0b, 0xde, 0x9d, 0x43, 0xc3, 0x67, 0x30, 0xc0,
|
||||
0x37, 0xc0, 0xa2, 0xa4, 0x44, 0x09, 0xee, 0x4e, 0x4d, 0xbd, 0x1b, 0xb0, 0x95, 0x62, 0xa7, 0x35,
|
||||
0xb7, 0x2b, 0xa7, 0x4a, 0x91, 0xac, 0xba, 0x36, 0xf5, 0xed, 0xda, 0x2f, 0xc5, 0xb8, 0xd2, 0x27,
|
||||
0xdb, 0x27, 0xa7, 0x61, 0xe7, 0xf9, 0x69, 0xd8, 0x79, 0x71, 0x1a, 0x76, 0x7e, 0x9c, 0x84, 0xde,
|
||||
0xc9, 0x24, 0xf4, 0x9e, 0x4f, 0x42, 0xef, 0xc5, 0x24, 0xf4, 0xfe, 0x9e, 0x84, 0xde, 0x6f, 0xff,
|
||||
0x84, 0x9d, 0x6f, 0xfc, 0xd1, 0xee, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x46, 0xb3, 0xb5, 0x00,
|
||||
0xc3, 0x09, 0x00, 0x00,
|
||||
// 911 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4b, 0x6b, 0x24, 0x45,
|
||||
0x1c, 0x9f, 0x9e, 0xcd, 0x24, 0x93, 0xca, 0x98, 0xdd, 0x2d, 0x96, 0x65, 0xc8, 0xa1, 0x13, 0x5a,
|
||||
0x90, 0x28, 0xa6, 0xda, 0x04, 0x91, 0x3d, 0x88, 0x8f, 0x56, 0x57, 0xc4, 0xcd, 0x2e, 0xd4, 0x06,
|
||||
0x17, 0x44, 0x5c, 0x2b, 0x3d, 0xb5, 0x9d, 0xda, 0x99, 0xae, 0x6a, 0xaa, 0x6a, 0x66, 0xcd, 0x41,
|
||||
0x11, 0x04, 0xf1, 0xe0, 0x41, 0xfc, 0x2c, 0x7e, 0x00, 0x8f, 0x39, 0x2e, 0x78, 0xd9, 0x53, 0x30,
|
||||
0xe3, 0xb7, 0xf0, 0x24, 0x55, 0x5d, 0x5d, 0xdd, 0x33, 0xc9, 0x62, 0x1e, 0xe0, 0x29, 0xe9, 0xff,
|
||||
0xe3, 0xf7, 0xfb, 0xbf, 0x6b, 0xc0, 0x7b, 0x19, 0xd3, 0x07, 0xe3, 0x7d, 0x94, 0x8a, 0x3c, 0x16,
|
||||
0x05, 0xe5, 0x5b, 0xe9, 0x68, 0xac, 0x34, 0x95, 0x5b, 0x39, 0xe1, 0x24, 0xa3, 0x39, 0xe5, 0x3a,
|
||||
0x26, 0x05, 0x8b, 0x9f, 0x09, 0x39, 0x8c, 0x27, 0xdb, 0x71, 0x46, 0x39, 0x95, 0x44, 0xd3, 0x01,
|
||||
0x2a, 0xa4, 0xd0, 0x02, 0xa2, 0xda, 0x1f, 0x19, 0xff, 0xc7, 0xce, 0xff, 0x71, 0xed, 0x8f, 0x48,
|
||||
0xc1, 0x90, 0xf1, 0x47, 0x93, 0xed, 0xb5, 0xad, 0x06, 0x5f, 0x26, 0x32, 0x11, 0x5b, 0x98, 0xfd,
|
||||
0xf1, 0x13, 0xfb, 0x65, 0x3f, 0xec, 0x7f, 0x25, 0xfc, 0xda, 0xdb, 0xc3, 0x3b, 0x0a, 0x31, 0x61,
|
||||
0x42, 0xc8, 0x49, 0x7a, 0xc0, 0x38, 0x95, 0x87, 0x71, 0x31, 0xcc, 0x8c, 0x40, 0xc5, 0x39, 0xd5,
|
||||
0xe4, 0x8c, 0xa0, 0xd6, 0xe2, 0x97, 0x79, 0xc9, 0x31, 0xd7, 0x2c, 0xa7, 0xa7, 0x1c, 0xde, 0xf9,
|
||||
0x2f, 0x07, 0x95, 0x1e, 0xd0, 0x9c, 0xcc, 0xfb, 0x45, 0x0a, 0x74, 0x77, 0x09, 0x67, 0x4f, 0xa8,
|
||||
0xd2, 0x30, 0x03, 0x3d, 0x49, 0x9e, 0x7d, 0xf2, 0xad, 0xa6, 0x5c, 0x31, 0xc1, 0xfb, 0xc1, 0x46,
|
||||
0xb0, 0xb9, 0xb2, 0xb3, 0x85, 0x4a, 0x68, 0xd4, 0x84, 0x46, 0xc5, 0x30, 0x43, 0x0e, 0x1a, 0xe1,
|
||||
0x86, 0x53, 0x72, 0xeb, 0xe8, 0x78, 0xbd, 0x35, 0x3d, 0x5e, 0xef, 0x35, 0xa5, 0x78, 0x06, 0x38,
|
||||
0xfa, 0xb9, 0x0d, 0x6e, 0x56, 0xac, 0x1f, 0x09, 0x3e, 0x60, 0x9a, 0x09, 0x0e, 0xbf, 0x07, 0x3d,
|
||||
0x49, 0x95, 0x18, 0xcb, 0x94, 0xee, 0x52, 0x4d, 0x1c, 0xfd, 0xc7, 0x17, 0xec, 0x0f, 0xaa, 0x80,
|
||||
0x71, 0x03, 0xab, 0x11, 0x55, 0x43, 0x8a, 0x67, 0xf8, 0xa0, 0x02, 0x20, 0xad, 0x82, 0x51, 0xfd,
|
||||
0xf6, 0xc6, 0xb5, 0xcd, 0x95, 0x9d, 0xf7, 0x2f, 0xca, 0xfe, 0x50, 0x13, 0x3d, 0x56, 0x3e, 0xa9,
|
||||
0x04, 0x3a, 0x62, 0xe0, 0x45, 0x0a, 0x37, 0x68, 0xa2, 0xdf, 0xdb, 0xe0, 0xd6, 0x59, 0x11, 0xc3,
|
||||
0xd7, 0xc1, 0x92, 0x90, 0x03, 0xc6, 0xc9, 0xc8, 0x16, 0xa2, 0x93, 0x5c, 0x77, 0x48, 0x4b, 0x0f,
|
||||
0x4a, 0x31, 0xae, 0xf4, 0xf0, 0x55, 0xd0, 0xc9, 0xa4, 0x18, 0x17, 0xfd, 0xf6, 0x46, 0xb0, 0xb9,
|
||||
0x9c, 0xbc, 0xe2, 0x0c, 0x3b, 0x9f, 0x1a, 0x21, 0x2e, 0x75, 0x06, 0x6f, 0x42, 0xa5, 0xed, 0xeb,
|
||||
0x35, 0x6b, 0xe6, 0xf1, 0xbe, 0x28, 0xc5, 0xb8, 0xd2, 0xc3, 0x0d, 0xb0, 0x30, 0x64, 0x7c, 0xd0,
|
||||
0x5f, 0xb0, 0x76, 0x3d, 0x67, 0xb7, 0xf0, 0x39, 0xe3, 0x03, 0x6c, 0x35, 0xf0, 0x4d, 0xd0, 0xad,
|
||||
0x4a, 0xd7, 0xef, 0x58, 0xab, 0x1b, 0xce, 0xaa, 0x5b, 0x25, 0x81, 0xbd, 0x85, 0xc1, 0xe3, 0x24,
|
||||
0xa7, 0xfd, 0xc5, 0x59, 0xbc, 0xfb, 0x24, 0xa7, 0xd8, 0x6a, 0x60, 0x0c, 0x96, 0xcd, 0x5f, 0x55,
|
||||
0x90, 0x94, 0xf6, 0x97, 0xac, 0xd9, 0x4d, 0x67, 0xb6, 0x7c, 0xbf, 0x52, 0xe0, 0xda, 0x26, 0xfa,
|
||||
0x25, 0x00, 0xb7, 0xe7, 0xcb, 0x56, 0x96, 0x1e, 0x4a, 0xb0, 0x9c, 0x3b, 0x4d, 0xd5, 0xc5, 0x0f,
|
||||
0x2f, 0x3b, 0x43, 0x75, 0x1f, 0x7d, 0x38, 0x95, 0x4a, 0xe1, 0x9a, 0x26, 0xfa, 0xa3, 0x0d, 0x7a,
|
||||
0x95, 0xe2, 0x91, 0x90, 0x43, 0xf8, 0x0d, 0xe8, 0x9a, 0xd5, 0x1e, 0x10, 0x3f, 0xc7, 0x6f, 0xbd,
|
||||
0x74, 0x8d, 0xcc, 0x21, 0x40, 0xc6, 0xda, 0x30, 0x3f, 0xd8, 0x7f, 0x4a, 0x53, 0x6d, 0x67, 0xd6,
|
||||
0x8f, 0x4e, 0x2d, 0xc3, 0x1e, 0x15, 0xee, 0x83, 0x05, 0x55, 0xd0, 0xd4, 0xf6, 0x7c, 0x65, 0xe7,
|
||||
0x83, 0xcb, 0x66, 0x68, 0xa2, 0x7d, 0x58, 0xd0, 0xb4, 0x6e, 0x8b, 0xf9, 0xc2, 0x16, 0x1b, 0x3e,
|
||||
0x05, 0x8b, 0xca, 0x16, 0xd5, 0x8e, 0xcc, 0xca, 0x4e, 0x72, 0x25, 0x16, 0x8b, 0x94, 0xac, 0x3a,
|
||||
0x9e, 0xc5, 0xf2, 0x1b, 0x3b, 0x86, 0xe8, 0xcf, 0x00, 0xdc, 0x68, 0x9a, 0xdf, 0x63, 0x4a, 0xc3,
|
||||
0xaf, 0x4e, 0x95, 0x11, 0x9d, 0xaf, 0x8c, 0xc6, 0xdb, 0x16, 0xd1, 0xcf, 0x65, 0x25, 0x69, 0x94,
|
||||
0x90, 0x80, 0x0e, 0xd3, 0x34, 0xaf, 0xa6, 0xe4, 0xdd, 0xab, 0x64, 0x57, 0x6f, 0xdd, 0x67, 0x06,
|
||||
0x12, 0x97, 0xc8, 0xd1, 0x8f, 0x73, 0x59, 0x99, 0xe2, 0x42, 0x01, 0xba, 0x06, 0x62, 0x24, 0xc8,
|
||||
0xc0, 0x65, 0x75, 0xe9, 0x01, 0x55, 0x7b, 0x34, 0x2f, 0x46, 0x44, 0xd3, 0x3a, 0xd1, 0x47, 0x0e,
|
||||
0x1a, 0x7b, 0x92, 0xe8, 0xb7, 0x36, 0x80, 0xa7, 0x5b, 0x31, 0x77, 0xf0, 0x82, 0xff, 0xe5, 0xe0,
|
||||
0xc1, 0x9f, 0x02, 0xb0, 0x2a, 0x67, 0x36, 0xd6, 0x8d, 0xf0, 0xdd, 0xab, 0x1e, 0x7a, 0x37, 0x60,
|
||||
0xb7, 0x5d, 0x00, 0xab, 0xb3, 0x72, 0x3c, 0xc7, 0x1a, 0x7d, 0x57, 0xbf, 0x41, 0xbe, 0x8a, 0xf0,
|
||||
0xa0, 0x79, 0x3c, 0xca, 0x8a, 0xdc, 0xb9, 0x6c, 0x5c, 0x75, 0x4b, 0x7c, 0xa4, 0x8d, 0x93, 0x71,
|
||||
0xdc, 0x06, 0xd7, 0xe7, 0x6a, 0x67, 0x0e, 0xa5, 0x3e, 0x2c, 0xa8, 0x1d, 0x8a, 0xc6, 0xa1, 0xdc,
|
||||
0x3b, 0x2c, 0x28, 0xb6, 0x1a, 0xf8, 0xb5, 0xdf, 0xc8, 0xf2, 0xd6, 0xdf, 0x9d, 0xdd, 0xa6, 0x7f,
|
||||
0x8e, 0xd7, 0xcf, 0xf5, 0x7b, 0x03, 0x79, 0xce, 0xd9, 0x2d, 0x84, 0x13, 0x00, 0x47, 0x44, 0xe9,
|
||||
0x3d, 0x49, 0xb8, 0xb2, 0xfa, 0x3d, 0x96, 0x53, 0xb7, 0xfd, 0x6f, 0x9c, 0x6f, 0xf5, 0x8c, 0x47,
|
||||
0xb2, 0xe6, 0xe2, 0x82, 0xf7, 0x4e, 0xa1, 0xe1, 0x33, 0x18, 0xe0, 0x6b, 0x60, 0x51, 0x52, 0xa2,
|
||||
0x04, 0x77, 0x8f, 0x8e, 0xbf, 0x12, 0xd8, 0x4a, 0xb1, 0xd3, 0x9a, 0x57, 0x2c, 0xa7, 0x4a, 0x91,
|
||||
0xac, 0x7a, 0x77, 0xfc, 0x2b, 0xb6, 0x5b, 0x8a, 0x71, 0xa5, 0x4f, 0x36, 0x8f, 0x4e, 0xc2, 0xd6,
|
||||
0xf3, 0x93, 0xb0, 0xf5, 0xe2, 0x24, 0x6c, 0xfd, 0x30, 0x0d, 0x83, 0xa3, 0x69, 0x18, 0x3c, 0x9f,
|
||||
0x86, 0xc1, 0x8b, 0x69, 0x18, 0xfc, 0x35, 0x0d, 0x83, 0x5f, 0xff, 0x0e, 0x5b, 0x5f, 0xb6, 0x27,
|
||||
0xdb, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xd8, 0x4c, 0x96, 0x74, 0x42, 0x0a, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *Manifest) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *Manifest) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *Manifest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
{
|
||||
size, err := m.RawExtension.MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintGenerated(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *ManifestCondition) Marshal() (dAtA []byte, err error) {
|
||||
@@ -697,10 +759,10 @@ func (m *ManifestsTemplate) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Manifests) > 0 {
|
||||
for iNdEx := len(m.Manifests) - 1; iNdEx >= 0; iNdEx-- {
|
||||
if len(m.Manifest) > 0 {
|
||||
for iNdEx := len(m.Manifest) - 1; iNdEx >= 0; iNdEx-- {
|
||||
{
|
||||
size, err := m.Manifests[iNdEx].MarshalToSizedBuffer(dAtA[:i])
|
||||
size, err := m.Manifest[iNdEx].MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -708,7 +770,7 @@ func (m *ManifestsTemplate) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i = encodeVarintGenerated(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
@@ -778,6 +840,17 @@ func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int {
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *Manifest) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = m.RawExtension.Size()
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *ManifestCondition) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
@@ -898,8 +971,8 @@ func (m *ManifestsTemplate) Size() (n int) {
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Manifests) > 0 {
|
||||
for _, e := range m.Manifests {
|
||||
if len(m.Manifest) > 0 {
|
||||
for _, e := range m.Manifest {
|
||||
l = e.Size()
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
@@ -932,6 +1005,16 @@ func sovGenerated(x uint64) (n int) {
|
||||
func sozGenerated(x uint64) (n int) {
|
||||
return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (this *Manifest) String() string {
|
||||
if this == nil {
|
||||
return "nil"
|
||||
}
|
||||
s := strings.Join([]string{`&Manifest{`,
|
||||
`RawExtension:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.RawExtension), "RawExtension", "runtime.RawExtension", 1), `&`, ``, 1) + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
}
|
||||
func (this *ManifestCondition) String() string {
|
||||
if this == nil {
|
||||
return "nil"
|
||||
@@ -1037,13 +1120,13 @@ func (this *ManifestsTemplate) String() string {
|
||||
if this == nil {
|
||||
return "nil"
|
||||
}
|
||||
repeatedStringForManifests := "[]RawExtension{"
|
||||
for _, f := range this.Manifests {
|
||||
repeatedStringForManifests += fmt.Sprintf("%v", f) + ","
|
||||
repeatedStringForManifest := "[]Manifest{"
|
||||
for _, f := range this.Manifest {
|
||||
repeatedStringForManifest += strings.Replace(strings.Replace(f.String(), "Manifest", "Manifest", 1), `&`, ``, 1) + ","
|
||||
}
|
||||
repeatedStringForManifests += "}"
|
||||
repeatedStringForManifest += "}"
|
||||
s := strings.Join([]string{`&ManifestsTemplate{`,
|
||||
`Manifests:` + repeatedStringForManifests + `,`,
|
||||
`Manifest:` + repeatedStringForManifest + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
@@ -1070,6 +1153,92 @@ func valueToStringGenerated(v interface{}) string {
|
||||
pv := reflect.Indirect(rv).Interface()
|
||||
return fmt.Sprintf("*%v", pv)
|
||||
}
|
||||
func (m *Manifest) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: Manifest: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: Manifest: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field RawExtension", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if err := m.RawExtension.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenerated(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if (iNdEx + skippy) < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *ManifestCondition) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
@@ -2048,9 +2217,9 @@ func (m *ManifestsTemplate) Unmarshal(dAtA []byte) error {
|
||||
return fmt.Errorf("proto: ManifestsTemplate: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 2:
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Manifests", wireType)
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Manifest", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
@@ -2077,8 +2246,8 @@ func (m *ManifestsTemplate) Unmarshal(dAtA []byte) error {
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Manifests = append(m.Manifests, runtime.RawExtension{})
|
||||
if err := m.Manifests[len(m.Manifests)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
m.Manifest = append(m.Manifest, Manifest{})
|
||||
if err := m.Manifest[len(m.Manifest)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
|
||||
9
vendor/github.com/open-cluster-management/api/work/v1/generated.proto
generated
vendored
9
vendor/github.com/open-cluster-management/api/work/v1/generated.proto
generated
vendored
@@ -12,6 +12,13 @@ import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto";
|
||||
// Package-wide variables from generator "generated".
|
||||
option go_package = "v1";
|
||||
|
||||
// Manifest represents a resource to be deployed on spoke cluster
|
||||
message Manifest {
|
||||
// +kubebuilder:validation:EmbeddedResource
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
optional k8s.io.apimachinery.pkg.runtime.RawExtension rawExtension = 1;
|
||||
}
|
||||
|
||||
// ManifestCondition represents the conditions of the resources deployed on
|
||||
// spoke cluster
|
||||
message ManifestCondition {
|
||||
@@ -122,7 +129,7 @@ message ManifestWorkStatus {
|
||||
message ManifestsTemplate {
|
||||
// Manifests represents a list of kuberenetes resources to be deployed on the spoke cluster.
|
||||
// +optional
|
||||
repeated k8s.io.apimachinery.pkg.runtime.RawExtension manifests = 2;
|
||||
repeated Manifest manifests = 1;
|
||||
}
|
||||
|
||||
// StatusCondition contains condition information for a spoke work.
|
||||
|
||||
9
vendor/github.com/open-cluster-management/api/work/v1/types.go
generated
vendored
9
vendor/github.com/open-cluster-management/api/work/v1/types.go
generated
vendored
@@ -55,11 +55,18 @@ type ManifestWorkSpec struct {
|
||||
Workload ManifestsTemplate `json:"workload,omitempty" protobuf:"bytes,1,opt,name=workload"`
|
||||
}
|
||||
|
||||
// Manifest represents a resource to be deployed on spoke cluster
|
||||
type Manifest struct {
|
||||
// +kubebuilder:validation:EmbeddedResource
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
runtime.RawExtension `json:",inline" protobuf:"bytes,1,opt,name=rawExtension"`
|
||||
}
|
||||
|
||||
// ManifestsTemplate represents the manifest workload to be deployed on spoke cluster
|
||||
type ManifestsTemplate struct {
|
||||
// Manifests represents a list of kuberenetes resources to be deployed on the spoke cluster.
|
||||
// +optional
|
||||
Manifests []runtime.RawExtension `json:"manifests,omitempty" protobuf:"bytes,2,rep,name=manifests"`
|
||||
Manifest []Manifest `json:"manifests,omitempty" protobuf:"bytes,1,rep,name=manifests"`
|
||||
}
|
||||
|
||||
// ManifestResourceMeta represents the gvk, gvr, name and namespace of a resoure
|
||||
|
||||
23
vendor/github.com/open-cluster-management/api/work/v1/zz_generated.deepcopy.go
generated
vendored
23
vendor/github.com/open-cluster-management/api/work/v1/zz_generated.deepcopy.go
generated
vendored
@@ -8,6 +8,23 @@ import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Manifest) DeepCopyInto(out *Manifest) {
|
||||
*out = *in
|
||||
in.RawExtension.DeepCopyInto(&out.RawExtension)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Manifest.
|
||||
func (in *Manifest) DeepCopy() *Manifest {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Manifest)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ManifestCondition) DeepCopyInto(out *ManifestCondition) {
|
||||
*out = *in
|
||||
@@ -176,9 +193,9 @@ func (in *ManifestWorkStatus) DeepCopy() *ManifestWorkStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ManifestsTemplate) DeepCopyInto(out *ManifestsTemplate) {
|
||||
*out = *in
|
||||
if in.Manifests != nil {
|
||||
in, out := &in.Manifests, &out.Manifests
|
||||
*out = make([]runtime.RawExtension, len(*in))
|
||||
if in.Manifest != nil {
|
||||
in, out := &in.Manifest, &out.Manifest
|
||||
*out = make([]Manifest, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
|
||||
@@ -11,6 +11,14 @@ package v1
|
||||
// Those methods can be generated by using hack/update-swagger-docs.sh
|
||||
|
||||
// AUTO-GENERATED FUNCTIONS START HERE
|
||||
var map_Manifest = map[string]string{
|
||||
"": "Manifest represents a resource to be deployed on spoke cluster",
|
||||
}
|
||||
|
||||
func (Manifest) SwaggerDoc() map[string]string {
|
||||
return map_Manifest
|
||||
}
|
||||
|
||||
var map_ManifestCondition = map[string]string{
|
||||
"": "ManifestCondition represents the conditions of the resources deployed on spoke cluster",
|
||||
"resourceMeta": "ResourceMeta represents the gvk, name and namespace of a resoure",
|
||||
|
||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@@ -89,7 +89,7 @@ github.com/modern-go/concurrent
|
||||
github.com/modern-go/reflect2
|
||||
# github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
|
||||
github.com/munnerz/goautoneg
|
||||
# github.com/open-cluster-management/api v0.0.0-20200506150956-355c9d6ef16b
|
||||
# github.com/open-cluster-management/api v0.0.0-20200512021938-5f0d5c12ea67
|
||||
github.com/open-cluster-management/api/client/nucleus/clientset/versioned
|
||||
github.com/open-cluster-management/api/client/nucleus/clientset/versioned/fake
|
||||
github.com/open-cluster-management/api/client/nucleus/clientset/versioned/scheme
|
||||
|
||||
Reference in New Issue
Block a user