Skip to content

Commit

Permalink
Introduce API for MultiClusterService (#461)
Browse files Browse the repository at this point in the history
* Introduce MultiClusterService API
  • Loading branch information
wahabmk authored Oct 10, 2024
1 parent be19807 commit 8bad252
Show file tree
Hide file tree
Showing 21 changed files with 666 additions and 61 deletions.
8 changes: 8 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,12 @@ resources:
kind: Credential
path: github.com/Mirantis/hmc/api/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
controller: true
domain: hmc.mirantis.com
group: hmc.mirantis.com
kind: MultiClusterService
path: github.com/Mirantis/hmc/api/v1alpha1
version: v1alpha1
version: "3"
44 changes: 19 additions & 25 deletions api/v1alpha1/managedcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,26 +64,6 @@ const (
ProgressingReason string = "Progressing"
)

// ManagedClusterServiceSpec represents a Service within ManagedCluster
type ManagedClusterServiceSpec struct {
// Template is a reference to a Template object located in the same namespace.
// +kubebuilder:validation:MinLength=1
Template string `json:"template"`
// Disable can be set to disable handling of this service.
// +optional
Disable bool `json:"disable"`
// Name is the chart release.
// +kubebuilder:validation:MinLength=1
Name string `json:"name"`
// Namespace is the namespace the release will be installed in.
// It will default to Name if not provided.
// +optional
Namespace string `json:"namespace"`
// Values is the helm values to be passed to the template.
// +optional
Values *apiextensionsv1.JSON `json:"values,omitempty"`
}

// ManagedClusterSpec defines the desired state of ManagedCluster
type ManagedClusterSpec struct {
// Config allows to provide parameters for template customization.
Expand All @@ -94,14 +74,28 @@ type ManagedClusterSpec struct {
// +kubebuilder:validation:MinLength=1

// Template is a reference to a Template object located in the same namespace.
Template string `json:"template"`
// DryRun specifies whether the template should be applied after validation or only validated.
DryRun bool `json:"dryRun,omitempty"`
Template string `json:"template"`
Credential string `json:"credential,omitempty"`
// Services is a list of services created via ServiceTemplates
// that could be installed on the target cluster.
// +optional
Services []ManagedClusterServiceSpec `json:"services,omitempty"`
Services []ServiceSpec `json:"services,omitempty"`

// +kubebuilder:default:=100
// +kubebuilder:validation:Minimum=1
// +kubebuilder:validation:Maximum=2147483646

// Priority sets the priority for the services defined in this spec.
// Higher value means higher priority and lower means lower.
// In case of conflict with another object managing the service,
// the one with higher priority will get to deploy its services.
Priority int32 `json:"priority,omitempty"`
// DryRun specifies whether the template should be applied after validation or only validated.
DryRun bool `json:"dryRun,omitempty"`
// StopOnConflict specifies what to do in case of a conflict.
// E.g. If another object is already managing a service.
// By default the remaining services will be deployed even if conflict is detected.
// If set to true, the deployment will stop after encountering the first conflict.
StopOnConflict bool `json:"stopOnConflict,omitempty"`
}

// ManagedClusterStatus defines the observed state of ManagedCluster
Expand Down
101 changes: 101 additions & 0 deletions api/v1alpha1/multiclusterservice_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2024
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package v1alpha1

import (
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// ServiceSpec represents a Service to be managed
type ServiceSpec struct {
// Values is the helm values to be passed to the template.
Values *apiextensionsv1.JSON `json:"values,omitempty"`

// +kubebuilder:validation:MinLength=1

// Template is a reference to a Template object located in the same namespace.
Template string `json:"template"`

// +kubebuilder:validation:MinLength=1

// Name is the chart release.
Name string `json:"name"`
// Namespace is the namespace the release will be installed in.
// It will default to Name if not provided.
Namespace string `json:"namespace,omitempty"`
// Disable can be set to disable handling of this service.
Disable bool `json:"disable,omitempty"`
}

// MultiClusterServiceSpec defines the desired state of MultiClusterService
type MultiClusterServiceSpec struct {
// ClusterSelector identifies target clusters to manage services on.
ClusterSelector metav1.LabelSelector `json:"clusterSelector,omitempty"`
// Services is a list of services created via ServiceTemplates
// that could be installed on the target cluster.
Services []ServiceSpec `json:"services,omitempty"`

// +kubebuilder:default:=100
// +kubebuilder:validation:Minimum=1
// +kubebuilder:validation:Maximum=2147483646

// Priority sets the priority for the services defined in this spec.
// Higher value means higher priority and lower means lower.
// In case of conflict with another object managing the service,
// the one with higher priority will get to deploy its services.
Priority int32 `json:"priority,omitempty"`
// StopOnConflict specifies what to do in case of a conflict.
// E.g. If another object is already managing a service.
// By default the remaining services will be deployed even if conflict is detected.
// If set to true, the deployment will stop after encountering the first conflict.
StopOnConflict bool `json:"stopOnConflict,omitempty"`
}

// MultiClusterServiceStatus defines the observed state of MultiClusterService
//
// TODO(https://github.com/Mirantis/hmc/issues/460):
// If this status ends up being common with ManagedClusterStatus,
// then make a common status struct that can be shared by both.
type MultiClusterServiceStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:scope=Cluster

// MultiClusterService is the Schema for the multiclusterservices API
type MultiClusterService struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec MultiClusterServiceSpec `json:"spec,omitempty"`
Status MultiClusterServiceStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// MultiClusterServiceList contains a list of MultiClusterService
type MultiClusterServiceList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []MultiClusterService `json:"items"`
}

func init() {
SchemeBuilder.Register(&MultiClusterService{}, &MultiClusterServiceList{})
}
139 changes: 118 additions & 21 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,12 @@ func main() {
os.Exit(1)
}

if err = (&controller.MultiClusterServiceReconciler{
Client: mgr.GetClient(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "MultiClusterService")
os.Exit(1)
}
// +kubebuilder:scaffold:builder

if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (
github.com/projectsveltos/addon-controller v0.39.0
github.com/projectsveltos/libsveltos v0.39.0
github.com/segmentio/analytics-go v3.1.0+incompatible
github.com/stretchr/testify v1.9.0
gopkg.in/yaml.v3 v3.0.1
helm.sh/helm/v3 v3.16.1
k8s.io/api v0.31.1
Expand Down Expand Up @@ -124,6 +125,7 @@ require (
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.20.4 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.60.0 // indirect
Expand Down
6 changes: 4 additions & 2 deletions internal/controller/managedcluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ func (r *ManagedClusterReconciler) updateServices(ctx context.Context, mc *hmc.M
}

opts = append(opts, sveltos.HelmChartOpts{
Values: svc.Values,
RepositoryURL: source.Spec.URL,
// We don't have repository name so chart name becomes repository name.
RepositoryName: tmpl.Spec.Helm.ChartName,
Expand All @@ -413,7 +414,6 @@ func (r *ManagedClusterReconciler) updateServices(ctx context.Context, mc *hmc.M
}(),
ChartVersion: tmpl.Spec.Helm.ChartVersion,
ReleaseName: svc.Name,
Values: svc.Values,
ReleaseNamespace: func() string {
if svc.Namespace != "" {
return svc.Namespace
Expand All @@ -440,7 +440,9 @@ func (r *ManagedClusterReconciler) updateServices(ctx context.Context, mc *hmc.M
Name: mc.Name,
UID: mc.UID,
},
HelmChartOpts: opts,
HelmChartOpts: opts,
Priority: mc.Spec.Priority,
StopOnConflict: mc.Spec.StopOnConflict,
}); err != nil {
return ctrl.Result{}, fmt.Errorf("failed to reconcile Profile: %w", err)
}
Expand Down
Loading

0 comments on commit 8bad252

Please sign in to comment.