diff --git a/pkg/core/manager/cluster/manager.go b/pkg/core/manager/cluster/manager.go index 84faea32..2c305b08 100644 --- a/pkg/core/manager/cluster/manager.go +++ b/pkg/core/manager/cluster/manager.go @@ -29,6 +29,7 @@ import ( yaml "gopkg.in/yaml.v3" v1 "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/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -101,8 +102,41 @@ func (c *ClusterManager) CreateCluster( return nil, err } unstructuredCluster := &unstructured.Unstructured{Object: unstructuredMap} - return client.DynamicClient.Resource(clusterGVR). + clusterCreated, err := client.DynamicClient.Resource(clusterGVR). Create(ctx, unstructuredCluster, metav1.CreateOptions{}) + + // Question: when use clusterapi.ClusterStatus, when use clusterv1beta1.ClusterStatus? + cluster := &clusterv1beta1.Cluster{} + err = runtime.DefaultUnstructuredConverter.FromUnstructured(clusterCreated.Object, cluster) + if err != nil { + return nil, err + } + + cluster = cluster.DeepCopy() + + validatedCondition := metav1.Condition{ + Type: clusterv1beta1.ValidatedCondition, + Status: metav1.ConditionTrue, + Reason: clusterv1beta1.ValidatedReason, + } + healthyCondition := metav1.Condition{ + Type: clusterv1beta1.ClusterHealthyCondition, + Status: metav1.ConditionTrue, + Reason: clusterv1beta1.ClusterHealthyReason, + } + + meta.SetStatusCondition(&cluster.Status.Conditions, validatedCondition) + meta.SetStatusCondition(&cluster.Status.Conditions, healthyCondition) + cluster.Status.APIServer = restConfig.Host + cluster.Status.Healthy = true + // TODO: Set cluster.Status.Version later in reconcile + + unstructuredMap, err = runtime.DefaultUnstructuredConverter.ToUnstructured(cluster) + if err != nil { + return nil, err + } + unstructuredCluster = &unstructured.Unstructured{Object: unstructuredMap} + return client.DynamicClient.Resource(clusterGVR).Update(ctx, unstructuredCluster, metav1.UpdateOptions{}) } // UpdateMetadata updates cluster by name with a full payload diff --git a/pkg/kubernetes/apis/cluster/types.go b/pkg/kubernetes/apis/cluster/types.go index 3eb3b21e..a788f3b9 100644 --- a/pkg/kubernetes/apis/cluster/types.go +++ b/pkg/kubernetes/apis/cluster/types.go @@ -28,6 +28,20 @@ const ( CredentialTypeOIDC CredentialType = "OIDC" ) +const ( + ValidatedCondition = "Validated" + ClusterHealthyCondition = "ClusterHealthy" +) + +const ( + InvalidConfigReason = "InvalidConfig" + ValidatedReason = "Validated" + + ClusterHealthyReason = "Healthy" + ClusterUnhealthyReason = "Unhealthy" + ClusterNotReachableReason = "NotReachable" +) + // +genclient // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -61,7 +75,10 @@ type ClusterSpec struct { } type ClusterStatus struct { - Healthy bool `json:"healthy,omitempty"` + Healthy bool `json:"healthy,omitempty"` + APIServer string `json:"apiserver,omitempty"` + Version string `json:"version,omitempty"` + Conditions []metav1.Condition `json:"conditions,omitempty"` } type ClusterAccess struct { diff --git a/pkg/kubernetes/apis/cluster/v1beta1/types.go b/pkg/kubernetes/apis/cluster/v1beta1/types.go index 4a80096a..fabbbfcc 100644 --- a/pkg/kubernetes/apis/cluster/v1beta1/types.go +++ b/pkg/kubernetes/apis/cluster/v1beta1/types.go @@ -28,6 +28,20 @@ const ( CredentialTypeOIDC CredentialType = "OIDC" ) +const ( + ValidatedCondition = "Validated" + ClusterHealthyCondition = "ClusterHealthy" +) + +const ( + InvalidConfigReason = "InvalidConfig" + ValidatedReason = "Validated" + + ClusterHealthyReason = "Healthy" + ClusterUnhealthyReason = "Unhealthy" + ClusterNotReachableReason = "NotReachable" +) + // +genclient // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -64,6 +78,12 @@ type ClusterSpec struct { type ClusterStatus struct { // +optional Healthy bool `json:"healthy,omitempty"` + // +optional + APIServer string `json:"apiserver,omitempty"` + // +optional + Version string `json:"version,omitempty"` + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` } type ClusterAccess struct { diff --git a/pkg/kubernetes/apis/cluster/v1beta1/zz_generated.conversion.go b/pkg/kubernetes/apis/cluster/v1beta1/zz_generated.conversion.go index 194e8c33..1b2a6f78 100644 --- a/pkg/kubernetes/apis/cluster/v1beta1/zz_generated.conversion.go +++ b/pkg/kubernetes/apis/cluster/v1beta1/zz_generated.conversion.go @@ -26,6 +26,7 @@ import ( unsafe "unsafe" cluster "github.com/KusionStack/karpor/pkg/kubernetes/apis/cluster" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -323,6 +324,9 @@ func Convert_cluster_ClusterSpec_To_v1beta1_ClusterSpec(in *cluster.ClusterSpec, func autoConvert_v1beta1_ClusterStatus_To_cluster_ClusterStatus(in *ClusterStatus, out *cluster.ClusterStatus, s conversion.Scope) error { out.Healthy = in.Healthy + out.APIServer = in.APIServer + out.Version = in.Version + out.Conditions = *(*[]v1.Condition)(unsafe.Pointer(&in.Conditions)) return nil } @@ -333,6 +337,9 @@ func Convert_v1beta1_ClusterStatus_To_cluster_ClusterStatus(in *ClusterStatus, o func autoConvert_cluster_ClusterStatus_To_v1beta1_ClusterStatus(in *cluster.ClusterStatus, out *ClusterStatus, s conversion.Scope) error { out.Healthy = in.Healthy + out.APIServer = in.APIServer + out.Version = in.Version + out.Conditions = *(*[]v1.Condition)(unsafe.Pointer(&in.Conditions)) return nil } diff --git a/pkg/kubernetes/apis/cluster/v1beta1/zz_generated.deepcopy.go b/pkg/kubernetes/apis/cluster/v1beta1/zz_generated.deepcopy.go index d3f23832..85d8648c 100644 --- a/pkg/kubernetes/apis/cluster/v1beta1/zz_generated.deepcopy.go +++ b/pkg/kubernetes/apis/cluster/v1beta1/zz_generated.deepcopy.go @@ -22,6 +22,7 @@ limitations under the License. package v1beta1 import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -31,7 +32,7 @@ func (in *Cluster) DeepCopyInto(out *Cluster) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status + in.Status.DeepCopyInto(&out.Status) return } @@ -193,6 +194,13 @@ func (in *ClusterSpec) DeepCopy() *ClusterSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) { *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } diff --git a/pkg/kubernetes/apis/cluster/zz_generated.deepcopy.go b/pkg/kubernetes/apis/cluster/zz_generated.deepcopy.go index 60094916..beacdbe0 100644 --- a/pkg/kubernetes/apis/cluster/zz_generated.deepcopy.go +++ b/pkg/kubernetes/apis/cluster/zz_generated.deepcopy.go @@ -22,6 +22,7 @@ limitations under the License. package cluster import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -31,7 +32,7 @@ func (in *Cluster) DeepCopyInto(out *Cluster) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status + in.Status.DeepCopyInto(&out.Status) return } @@ -193,6 +194,13 @@ func (in *ClusterSpec) DeepCopy() *ClusterSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) { *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } diff --git a/pkg/kubernetes/generated/informers/externalversions/cluster/v1beta1/cluster.go b/pkg/kubernetes/generated/informers/externalversions/cluster/v1beta1/cluster.go index 456fb061..21689c93 100644 --- a/pkg/kubernetes/generated/informers/externalversions/cluster/v1beta1/cluster.go +++ b/pkg/kubernetes/generated/informers/externalversions/cluster/v1beta1/cluster.go @@ -76,17 +76,14 @@ func NewFilteredClusterInformer(client versioned.Interface, resyncPeriod time.Du ) } -// defaultInformer provides a default implementation for the cluster informer using the given client and resync period. func (f *clusterInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { return NewFilteredClusterInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) } -// Informer returns the SharedIndexInformer for the cluster informer. func (f *clusterInformer) Informer() cache.SharedIndexInformer { return f.factory.InformerFor(&clusterv1beta1.Cluster{}, f.defaultInformer) } -// Lister returns the ClusterLister for the cluster informer. func (f *clusterInformer) Lister() v1beta1.ClusterLister { return v1beta1.NewClusterLister(f.Informer().GetIndexer()) } diff --git a/pkg/kubernetes/generated/informers/externalversions/factory.go b/pkg/kubernetes/generated/informers/externalversions/factory.go index 90cb7bd5..116160dd 100644 --- a/pkg/kubernetes/generated/informers/externalversions/factory.go +++ b/pkg/kubernetes/generated/informers/externalversions/factory.go @@ -113,7 +113,6 @@ func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResy return factory } -// Start starts all informers in the factory and waits for the stop channel to close before exiting. func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { f.lock.Lock() defer f.lock.Unlock() @@ -138,7 +137,6 @@ func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { } } -// Shutdown stops all running informers in the factory. func (f *sharedInformerFactory) Shutdown() { f.lock.Lock() f.shuttingDown = true @@ -148,7 +146,6 @@ func (f *sharedInformerFactory) Shutdown() { f.wg.Wait() } -// WaitForCacheSync waits for all started informers to sync with the cluster state. func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { informers := func() map[reflect.Type]cache.SharedIndexInformer { f.lock.Lock() @@ -251,12 +248,10 @@ type SharedInformerFactory interface { Search() search.Interface } -// Cluster returns the cluster informer. func (f *sharedInformerFactory) Cluster() cluster.Interface { return cluster.New(f, f.namespace, f.tweakListOptions) } -// Search returns the search informer. func (f *sharedInformerFactory) Search() search.Interface { return search.New(f, f.namespace, f.tweakListOptions) } diff --git a/pkg/kubernetes/generated/informers/externalversions/search/v1beta1/syncregistry.go b/pkg/kubernetes/generated/informers/externalversions/search/v1beta1/syncregistry.go index a01e732c..2f1edc17 100644 --- a/pkg/kubernetes/generated/informers/externalversions/search/v1beta1/syncregistry.go +++ b/pkg/kubernetes/generated/informers/externalversions/search/v1beta1/syncregistry.go @@ -76,17 +76,14 @@ func NewFilteredSyncRegistryInformer(client versioned.Interface, resyncPeriod ti ) } -// defaultInformer provides the default implementation for the shared informer used by the SyncRegistryInformer. func (f *syncRegistryInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { return NewFilteredSyncRegistryInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) } -// Informer returns the shared informer for the SyncRegistryInformer. func (f *syncRegistryInformer) Informer() cache.SharedIndexInformer { return f.factory.InformerFor(&searchv1beta1.SyncRegistry{}, f.defaultInformer) } -// Lister returns the lister for the SyncRegistryInformer. func (f *syncRegistryInformer) Lister() v1beta1.SyncRegistryLister { return v1beta1.NewSyncRegistryLister(f.Informer().GetIndexer()) } diff --git a/pkg/kubernetes/generated/informers/externalversions/search/v1beta1/syncresources.go b/pkg/kubernetes/generated/informers/externalversions/search/v1beta1/syncresources.go index 335d512f..5c386813 100644 --- a/pkg/kubernetes/generated/informers/externalversions/search/v1beta1/syncresources.go +++ b/pkg/kubernetes/generated/informers/externalversions/search/v1beta1/syncresources.go @@ -76,17 +76,14 @@ func NewFilteredSyncResourcesInformer(client versioned.Interface, resyncPeriod t ) } -// defaultInformer provides a default SharedIndexInformer implementation for SyncResources resources. func (f *syncResourcesInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { return NewFilteredSyncResourcesInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) } -// Informer returns the SharedIndexInformer for SyncResources resources. func (f *syncResourcesInformer) Informer() cache.SharedIndexInformer { return f.factory.InformerFor(&searchv1beta1.SyncResources{}, f.defaultInformer) } -// Lister returns the SyncResourcesLister for SyncResources resources. func (f *syncResourcesInformer) Lister() v1beta1.SyncResourcesLister { return v1beta1.NewSyncResourcesLister(f.Informer().GetIndexer()) } diff --git a/pkg/kubernetes/generated/informers/externalversions/search/v1beta1/transformrule.go b/pkg/kubernetes/generated/informers/externalversions/search/v1beta1/transformrule.go index 509aebd2..443efd2c 100644 --- a/pkg/kubernetes/generated/informers/externalversions/search/v1beta1/transformrule.go +++ b/pkg/kubernetes/generated/informers/externalversions/search/v1beta1/transformrule.go @@ -76,17 +76,14 @@ func NewFilteredTransformRuleInformer(client versioned.Interface, resyncPeriod t ) } -// defaultInformer provides a default implementation for the SharedIndexInformer interface. func (f *transformRuleInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { return NewFilteredTransformRuleInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) } -// Informer returns the SharedIndexInformer for TransformRule resources. func (f *transformRuleInformer) Informer() cache.SharedIndexInformer { return f.factory.InformerFor(&searchv1beta1.TransformRule{}, f.defaultInformer) } -// Lister returns the TransformRuleLister for TransformRule resources. func (f *transformRuleInformer) Lister() v1beta1.TransformRuleLister { return v1beta1.NewTransformRuleLister(f.Informer().GetIndexer()) } diff --git a/pkg/kubernetes/generated/openapi/zz_generated.openapi.go b/pkg/kubernetes/generated/openapi/zz_generated.openapi.go index 116b9869..4a7ea31a 100644 --- a/pkg/kubernetes/generated/openapi/zz_generated.openapi.go +++ b/pkg/kubernetes/generated/openapi/zz_generated.openapi.go @@ -382,9 +382,36 @@ func schema_kubernetes_apis_cluster_v1beta1_ClusterStatus(ref common.ReferenceCa Format: "", }, }, + "apiserver": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "version": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "conditions": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, + }, + }, }, }, }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, } }