Skip to content

Commit

Permalink
Expose additional sveltos settings for service deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
wahabmk committed Dec 20, 2024
1 parent 6abe75c commit 197c122
Show file tree
Hide file tree
Showing 15 changed files with 575 additions and 194 deletions.
6 changes: 3 additions & 3 deletions api/v1alpha1/indexers.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func ExtractServiceTemplateNamesFromManagedCluster(rawObj client.Object) []strin
}

templates := []string{}
for _, s := range cluster.Spec.Services {
for _, s := range cluster.Spec.ServiceSpec.Services {
templates = append(templates, s.Template)
}

Expand Down Expand Up @@ -204,8 +204,8 @@ func ExtractServiceTemplateNamesFromMultiClusterService(rawObj client.Object) []
return nil
}

templates := make([]string, len(mcs.Spec.Services))
for i, s := range mcs.Spec.Services {
templates := make([]string, len(mcs.Spec.ServiceSpec.Services))
for i, s := range mcs.Spec.ServiceSpec.Services {
templates[i] = s.Template
}

Expand Down
23 changes: 2 additions & 21 deletions api/v1alpha1/managedcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,29 +61,10 @@ type ManagedClusterSpec struct {
Template string `json:"template"`
// Name reference to the related Credentials object.
Credential string `json:"credential,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

// ServicesPriority 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.
ServicesPriority int32 `json:"servicesPriority,omitempty"`
// ServiceSpec is spec related to deployment of services.
ServiceSpec ServiceSpec `json:"serviceSpec,omitempty"`
// DryRun specifies whether the template should be applied after validation or only validated.
DryRun bool `json:"dryRun,omitempty"`

// +kubebuilder:default:=false

// 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
37 changes: 28 additions & 9 deletions api/v1alpha1/multiclusterservice_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package v1alpha1

import (
sveltosv1beta1 "github.com/projectsveltos/addon-controller/api/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand All @@ -37,8 +38,8 @@ const (
FetchServicesStatusSuccessCondition = "FetchServicesStatusSuccess"
)

// ServiceSpec represents a Service to be managed
type ServiceSpec struct {
// Service represents a Service to be deployed.
type Service struct {
// Values is the helm values to be passed to the chart used by the template.
// The string type is used in order to allow for templating.
Values string `json:"values,omitempty"`
Expand All @@ -57,27 +58,35 @@ type ServiceSpec struct {
// Namespace is the namespace the release will be installed in.
// It will default to Name if not provided.
Namespace string `json:"namespace,omitempty"`
// ValuesFrom can reference a ConfigMap or Secret containing helm values.
ValuesFrom []sveltosv1beta1.ValueFrom `json:"valuesFrom,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"`
// ServiceSpec contains all the spec related to deployment of services.
type ServiceSpec struct {
// Services is a list of services created via ServiceTemplates
// that could be installed on the target cluster.
Services []ServiceSpec `json:"services,omitempty"`
Services []Service `json:"services,omitempty"`
// TemplateResourceRefs is a list of resources to collect from the management cluster,
// the values from which can be used in templates.
TemplateResourceRefs []sveltosv1beta1.TemplateResourceRef `json:"templateResourceRefs,omitempty"`
// PolicyRefs is a list of kubernetes resources that need to be deployed in matching clusters.
// These resources may contain static values or leverage Go templates for dynamic customization.
// When expressed as templates, the values are rendered using data from resources
// (like Cluster & TemplateResourceRefs) within the management cluster before deployement.
PolicyRefs []sveltosv1beta1.PolicyRef `json:"policyRefs,omitempty"`

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

// ServicesPriority sets the priority for the services defined in this spec.
// 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.
ServicesPriority int32 `json:"servicesPriority,omitempty"`
Priority int32 `json:"priority,omitempty"`

// +kubebuilder:default:=false

Expand All @@ -86,6 +95,16 @@ type MultiClusterServiceSpec struct {
// 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"`
// Reload instances via rolling upgrade when a ConfigMap/Secret mounted as volume is modified.
Reload bool `json:"reload,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"`
// ServiceSpec is spec related to deployment of services.
ServiceSpec ServiceSpec `json:"serviceSpec,omitempty"`
}

// ServiceStatus contains details for the state of services.
Expand Down
50 changes: 40 additions & 10 deletions api/v1alpha1/zz_generated.deepcopy.go

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

11 changes: 7 additions & 4 deletions internal/controller/managedcluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ func (r *ManagedClusterReconciler) updateServices(ctx context.Context, mc *hmc.M
err = errors.Join(err, servicesErr)
}()

opts, err := sveltos.GetHelmChartOpts(ctx, r.Client, mc.Namespace, mc.Spec.Services)
opts, err := sveltos.GetHelmChartOpts(ctx, r.Client, mc.Namespace, mc.Spec.ServiceSpec.Services)
if err != nil {
return ctrl.Result{}, err
}
Expand All @@ -454,9 +454,12 @@ func (r *ManagedClusterReconciler) updateServices(ctx context.Context, mc *hmc.M
hmc.FluxHelmChartNameKey: mc.Name,
},
},
HelmChartOpts: opts,
Priority: mc.Spec.ServicesPriority,
StopOnConflict: mc.Spec.StopOnConflict,
HelmChartOpts: opts,
Priority: mc.Spec.ServiceSpec.Priority,
StopOnConflict: mc.Spec.ServiceSpec.StopOnConflict,
Reload: mc.Spec.ServiceSpec.Reload,
TemplateResourceRefs: mc.Spec.ServiceSpec.TemplateResourceRefs,
PolicyRefs: mc.Spec.ServiceSpec.PolicyRefs,
}); err != nil {
return ctrl.Result{}, fmt.Errorf("failed to reconcile Profile: %w", err)
}
Expand Down
10 changes: 6 additions & 4 deletions internal/controller/managedcluster_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,12 @@ var _ = Describe("ManagedCluster Controller", func() {
Spec: hmc.ManagedClusterSpec{
Template: templateName,
Credential: credentialName,
Services: []hmc.ServiceSpec{
{
Template: svcTemplateName,
Name: "test-svc-name",
ServiceSpec: hmc.ServiceSpec{
Services: []hmc.Service{
{
Template: svcTemplateName,
Name: "test-svc-name",
},
},
},
},
Expand Down
13 changes: 8 additions & 5 deletions internal/controller/multiclusterservice_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func (r *MultiClusterServiceReconciler) reconcileUpdate(ctx context.Context, mcs

// We are enforcing that MultiClusterService may only use
// ServiceTemplates that are present in the system namespace.
opts, err := sveltos.GetHelmChartOpts(ctx, r.Client, r.SystemNamespace, mcs.Spec.Services)
opts, err := sveltos.GetHelmChartOpts(ctx, r.Client, r.SystemNamespace, mcs.Spec.ServiceSpec.Services)
if err != nil {
return ctrl.Result{}, err
}
Expand All @@ -128,10 +128,13 @@ func (r *MultiClusterServiceReconciler) reconcileUpdate(ctx context.Context, mcs
Name: mcs.Name,
UID: mcs.UID,
},
LabelSelector: mcs.Spec.ClusterSelector,
HelmChartOpts: opts,
Priority: mcs.Spec.ServicesPriority,
StopOnConflict: mcs.Spec.StopOnConflict,
LabelSelector: mcs.Spec.ClusterSelector,
HelmChartOpts: opts,
Priority: mcs.Spec.ServiceSpec.Priority,
StopOnConflict: mcs.Spec.ServiceSpec.StopOnConflict,
Reload: mcs.Spec.ServiceSpec.Reload,
TemplateResourceRefs: mcs.Spec.ServiceSpec.TemplateResourceRefs,
PolicyRefs: mcs.Spec.ServiceSpec.PolicyRefs,
}); err != nil {
return ctrl.Result{}, fmt.Errorf("failed to reconcile ClusterProfile: %w", err)
}
Expand Down
18 changes: 10 additions & 8 deletions internal/controller/multiclusterservice_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,14 +215,16 @@ var _ = Describe("MultiClusterService Controller", func() {
},
},
Spec: hmc.MultiClusterServiceSpec{
Services: []hmc.ServiceSpec{
{
Template: serviceTemplate1Name,
Name: helmChartReleaseName,
},
{
Template: serviceTemplate2Name,
Name: helmChartReleaseName,
ServiceSpec: hmc.ServiceSpec{
Services: []hmc.Service{
{
Template: serviceTemplate1Name,
Name: helmChartReleaseName,
},
{
Template: serviceTemplate2Name,
Name: helmChartReleaseName,
},
},
},
},
Expand Down
28 changes: 19 additions & 9 deletions internal/sveltos/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,20 @@ import (
)

type ReconcileProfileOpts struct {

Check failure on line 35 in internal/sveltos/profile.go

View workflow job for this annotation

GitHub Actions / Build and Unit Test

fieldalignment: struct with 104 pointer bytes could be 96 (govet)
OwnerReference *metav1.OwnerReference
LabelSelector metav1.LabelSelector
HelmChartOpts []HelmChartOpts
Priority int32
StopOnConflict bool
OwnerReference *metav1.OwnerReference
LabelSelector metav1.LabelSelector
HelmChartOpts []HelmChartOpts
Priority int32
StopOnConflict bool
Reload bool
TemplateResourceRefs []sveltosv1beta1.TemplateResourceRef
PolicyRefs []sveltosv1beta1.PolicyRef
}

type HelmChartOpts struct {

Check failure on line 46 in internal/sveltos/profile.go

View workflow job for this annotation

GitHub Actions / Build and Unit Test

fieldalignment: struct with 136 pointer bytes could be 128 (govet)
CredentialsSecretRef *corev1.SecretReference
Values string
ValuesFrom []sveltosv1beta1.ValueFrom
RepositoryURL string
RepositoryName string
ChartName string
Expand Down Expand Up @@ -127,7 +131,7 @@ func ReconcileProfile(

// GetHelmChartOpts returns slice of helm chart options to use with Sveltos.
// Namespace is the namespace of the referred templates in services slice.
func GetHelmChartOpts(ctx context.Context, c client.Client, namespace string, services []hmc.ServiceSpec) ([]HelmChartOpts, error) {
func GetHelmChartOpts(ctx context.Context, c client.Client, namespace string, services []hmc.Service) ([]HelmChartOpts, error) {
l := ctrl.LoggerFrom(ctx)
opts := []HelmChartOpts{}

Expand Down Expand Up @@ -178,6 +182,7 @@ func GetHelmChartOpts(ctx context.Context, c client.Client, namespace string, se
chartName := chart.Spec.Chart
opt := HelmChartOpts{
Values: svc.Values,
ValuesFrom: svc.ValuesFrom,
RepositoryURL: repo.Spec.URL,
// We don't have repository name so chart name becomes repository name.
RepositoryName: chartName,
Expand Down Expand Up @@ -230,9 +235,12 @@ func GetSpec(opts *ReconcileProfileOpts) (*sveltosv1beta1.Spec, error) {
ClusterSelector: libsveltosv1beta1.Selector{
LabelSelector: opts.LabelSelector,
},
Tier: tier,
ContinueOnConflict: !opts.StopOnConflict,
HelmCharts: make([]sveltosv1beta1.HelmChart, 0, len(opts.HelmChartOpts)),
Tier: tier,
ContinueOnConflict: !opts.StopOnConflict,
HelmCharts: make([]sveltosv1beta1.HelmChart, 0, len(opts.HelmChartOpts)),
Reloader: opts.Reload,
TemplateResourceRefs: opts.TemplateResourceRefs,
PolicyRefs: opts.PolicyRefs,
}

for _, hc := range opts.HelmChartOpts {
Expand All @@ -259,6 +267,8 @@ func GetSpec(opts *ReconcileProfileOpts) (*sveltosv1beta1.Spec, error) {
}

helmChart.Values = hc.Values
helmChart.ValuesFrom = hc.ValuesFrom

spec.HelmCharts = append(spec.HelmCharts, helmChart)
}

Expand Down
Loading

0 comments on commit 197c122

Please sign in to comment.