Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion clm/cmd/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const applyUsage = `Apply component manifests to Kubernetes cluster`
type applyOptions struct {
valuesSources []string
createNamespace bool
targetNamespace string
targetName string
timeout time.Duration
}

Expand All @@ -51,6 +53,12 @@ func newApplyCmd() *cobra.Command {
name := args[0]
manifestSources := args[1:]
namespace := c.Flag("namespace").Value.String()
if options.targetNamespace == "" {
options.targetNamespace = namespace
}
if options.targetName == "" {
options.targetName = name
}

clnt, err := getClient(c.Flag("kubeconfig").Value.String())
if err != nil {
Expand All @@ -76,7 +84,7 @@ func newApplyCmd() *cobra.Command {
release, err := releaseClient.Get(context.TODO(), namespace, name)
if err != nil {
if apierrors.IsNotFound(err) {
release, err = releaseClient.Create(context.TODO(), namespace, name)
release, err = releaseClient.Create(context.TODO(), namespace, name, options.targetNamespace, options.targetName)
if err != nil {
return err
}
Expand All @@ -89,6 +97,10 @@ func newApplyCmd() *cobra.Command {
return fmt.Errorf("release %s/%s is being deleted; updates are not allowed in this state", release.GetNamespace(), release.GetName())
}

if release.GetTargetNamespace() != options.targetNamespace || release.GetTargetName() != options.targetName {
return fmt.Errorf("release %s/%s already exists with different target (namespace: %s, name: %s)", release.GetNamespace(), release.GetName(), release.GetTargetNamespace(), release.GetTargetName())
}

release.Revision += 1

objects, err := manifests.Generate(manifestSources, options.valuesSources, fullName, clnt, release)
Expand Down Expand Up @@ -168,6 +180,8 @@ func newApplyCmd() *cobra.Command {
flags := cmd.Flags()
flags.StringArrayVarP(&options.valuesSources, "values", "f", nil, "Path to values file in yaml format (can be repeated, values will be merged in order of appearance)")
flags.BoolVar(&options.createNamespace, "create-namespace", false, "Create release namespace if not existing")
flags.StringVar(&options.targetNamespace, "target-namespace", "", "Target deployment namespace for the release (defaults to the release namespace)")
flags.StringVar(&options.targetName, "target-name", "", "Target deployment name for the release (defaults to the release name)")
flags.DurationVar(&options.timeout, "timeout", 0, "Time to wait for the operation to complete (default is to wait forever)")

return cmd
Expand Down
6 changes: 4 additions & 2 deletions clm/cmd/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,14 @@ func newListCmd() *cobra.Command {
switch options.outputFormat {
case "table":
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n", "NAMESPACE", "NAME", "REVISION", "STATE", "OBJECTS", "READY", "COMPLETED", "CREATED", "UPDATED")
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n", "NAMESPACE", "NAME", "TARGET NAMESPACE", "TARGET NAME", "REVISION", "STATE", "OBJECTS", "READY", "COMPLETED", "CREATED", "UPDATED")
for _, release := range releases {
details := getReleaseDetails(release)
fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%d\t%d\t%d\t%s\t%s\t\n",
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%d\t%s\t%d\t%d\t%d\t%s\t%s\t\n",
details.Namespace,
details.Name,
details.TargetNamespace,
details.TargetName,
details.Revision,
details.State,
details.NumAllObjects,
Expand Down
2 changes: 2 additions & 0 deletions clm/cmd/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ func newStatusCmd() *cobra.Command {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
fmt.Fprintf(w, "%s:\t%s\t\n", "Namespace", details.Namespace)
fmt.Fprintf(w, "%s:\t%s\t\n", "Name", details.Name)
fmt.Fprintf(w, "%s:\t%s\t\n", "Target Namespace", details.TargetNamespace)
fmt.Fprintf(w, "%s:\t%s\t\n", "Target Name", details.TargetName)
fmt.Fprintf(w, "%s:\t%d\t\n", "Revision", details.Revision)
fmt.Fprintf(w, "%s:\t%s\t\n", "State", details.State)
fmt.Fprintf(w, "%s:\t%d\t\n", "Number of objects", details.NumAllObjects)
Expand Down
13 changes: 7 additions & 6 deletions clm/cmd/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import (
const templateUsage = `Render component manifests to standard output without applying them to the cluster`

type templateOptions struct {
valuesSources []string
valuesSources []string
targetNamespace string
targetName string
}

func newTemplateCmd() *cobra.Command {
Expand All @@ -42,12 +44,9 @@ func newTemplateCmd() *cobra.Command {
manifestSources := args[1:]
namespace := c.Flag("namespace").Value.String()

clnt, err := getClient(c.Flag("kubeconfig").Value.String())
if err != nil {
return err
}
clnt, _ := getClient(c.Flag("kubeconfig").Value.String())

release := release.NewRelease(namespace, name)
release := release.NewRelease(namespace, name, options.targetNamespace, options.targetName)
release.Revision += 1

objects, err := manifests.Generate(manifestSources, options.valuesSources, fullName, clnt, release)
Expand Down Expand Up @@ -83,6 +82,8 @@ func newTemplateCmd() *cobra.Command {

flags := cmd.Flags()
flags.StringArrayVarP(&options.valuesSources, "values", "f", nil, "Path to values file in yaml format (can be repeated, values will be merged in order of appearance)")
flags.StringVar(&options.targetNamespace, "target-namespace", "", "Target deployment namespace for the release (defaults to the release namespace)")
flags.StringVar(&options.targetName, "target-name", "", "Target deployment name for the release (defaults to the release name)")

return cmd
}
4 changes: 4 additions & 0 deletions clm/cmd/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ func formatTimestamp(t time.Time) string {
type releaseDetails struct {
Namespace string `json:"namespace"`
Name string `json:"name"`
TargetNamespace string `json:"targetNamespace"`
TargetName string `json:"targetName"`
Revision int64 `json:"revision"`
State string `json:"state"`
NumAllObjects int64 `json:"numAllObjects"`
Expand All @@ -93,6 +95,8 @@ func getReleaseDetails(release *release.Release) *releaseDetails {
return &releaseDetails{
Namespace: release.GetNamespace(),
Name: release.GetName(),
TargetNamespace: release.GetTargetNamespace(),
TargetName: release.GetTargetName(),
Revision: release.Revision,
State: string(release.State),
NumAllObjects: int64(len(release.Inventory)),
Expand Down
6 changes: 5 additions & 1 deletion clm/internal/manifests/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ type Component struct {
}

type ComponentSpec struct {
Values *apiextensionsv1.JSON `json:"values,omitempty"`
Namespace string `json:"namespace,omitempty"`
Name string `json:"name,omitempty"`
Values *apiextensionsv1.JSON `json:"values,omitempty"`
}

type ComponentStatus struct {
Expand Down Expand Up @@ -57,6 +59,8 @@ func componentFromRelease(release *release.Release, values map[string]any) *Comp
},
},
Spec: ComponentSpec{
Namespace: release.GetTargetNamespace(),
Name: release.GetTargetName(),
Values: &apiextensionsv1.JSON{
Raw: must(json.Marshal(values)),
},
Expand Down
2 changes: 1 addition & 1 deletion clm/internal/manifests/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func Generate(manifestSources []string, valuesSources []string, reconcilerName s
WithComponentNamespace(releaseComponent.Namespace).
WithComponentDigest(releaseComponent.Status.ProcessingDigest).
WithComponentRevision(releaseComponent.Status.Revision)
objects, err := generator.Generate(generateCtx, releaseComponent.Namespace, releaseComponent.Name, types.UnstructurableMap(allValues))
objects, err := generator.Generate(generateCtx, releaseComponent.Spec.Namespace, releaseComponent.Spec.Name, types.UnstructurableMap(allValues))
if err != nil {
return nil, err
}
Expand Down
4 changes: 3 additions & 1 deletion clm/internal/release/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,14 @@ func (c *Client) List(ctx context.Context, namespace string) ([]*Release, error)
return releases, nil
}

func (c *Client) Create(ctx context.Context, namespace string, name string) (*Release, error) {
func (c *Client) Create(ctx context.Context, namespace string, name string, targetNamespace string, targetName string) (*Release, error) {
now := time.Now()

release := &Release{
namespace: namespace,
name: name,
targetNamespace: targetNamespace,
targetName: targetName,
creationTimestamp: &now,
updateTimestamp: &now,
configMap: &corev1.ConfigMap{
Expand Down
35 changes: 32 additions & 3 deletions clm/internal/release/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (

const (
dataKeyVersion = "version"
dataKeyTargetNamespace = "targetNamespace"
dataKeyTargetName = "targetName"
dataKeyCreationTimestamp = "creationTimestamp"
dataKeyUpdateTimestamp = "updateTimestamp"
dataKeyRevision = "revision"
Expand All @@ -29,6 +31,8 @@ const (
type Release struct {
namespace string
name string
targetNamespace string
targetName string
creationTimestamp *time.Time
updateTimestamp *time.Time
configMap *corev1.ConfigMap
Expand All @@ -37,10 +41,12 @@ type Release struct {
State component.State
}

func NewRelease(namespace string, name string) *Release {
func NewRelease(namespace string, name string, targetNamespace string, targetName string) *Release {
return &Release{
namespace: namespace,
name: name,
namespace: namespace,
name: name,
targetNamespace: targetNamespace,
targetName: targetName,
}
}

Expand All @@ -52,6 +58,14 @@ func (r *Release) GetName() string {
return r.name
}

func (r *Release) GetTargetNamespace() string {
return r.targetNamespace
}

func (r *Release) GetTargetName() string {
return r.targetName
}

func (r *Release) GetDigest() string {
return sha256hex([]byte(fmt.Sprintf("%d", r.Revision)))
}
Expand All @@ -69,6 +83,18 @@ func (r *Release) GetUpdateTimestamp() *time.Time {
}

func (r *Release) importData() error {
if targetNamespaceData, ok := r.configMap.Data[dataKeyTargetNamespace]; ok {
r.targetNamespace = targetNamespaceData
} else {
r.targetNamespace = r.namespace
}

if targetNameData, ok := r.configMap.Data[dataKeyTargetName]; ok {
r.targetName = targetNameData
} else {
r.targetName = r.name
}

if creationTimestampData, ok := r.configMap.Data[dataKeyCreationTimestamp]; ok {
creationTimestamp, err := time.Parse(time.RFC3339, creationTimestampData)
if err != nil {
Expand Down Expand Up @@ -123,6 +149,9 @@ func (r *Release) exportData() error {

r.configMap.Data[dataKeyVersion] = "1"

r.configMap.Data[dataKeyTargetNamespace] = r.targetNamespace
r.configMap.Data[dataKeyTargetName] = r.targetName

if r.creationTimestamp != nil {
r.configMap.Data[dataKeyCreationTimestamp] = r.creationTimestamp.Format(time.RFC3339)
} else {
Expand Down