Skip to content
Merged
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
54 changes: 54 additions & 0 deletions .github/workflows/publish-clm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Publish clm

on:
release:
types: [published]

defaults:
run:
shell: bash

jobs:
deploy:
runs-on: [ubuntu-24.04]

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup go
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'

- name: Build
run: |
mkdir -p bin
for os in linux darwin; do
for arch in amd64 arm64; do
file=bin/clm-$os-$arch
echo "Building $file ..."
LDFLAGS=""
LDFLAGS+=" -X \"github.com/sap/component-operator-runtime/internal/version.version=${{ github.event.release.tag_name }}\""
LDFLAGS+=" -X \"github.com/sap/component-operator-runtime/internal/version.gitCommit=${{ github.sha }}\""
LDFLAGS+=" -X \"github.com/sap/component-operator-runtime/internal/version.gitTreeState=clean\""
GOOS=$os GOARCH=$arch go build -o $file -ldflags "$LDFLAGS" ./clm
done
done

- name: Upload
run: |
for os in linux darwin; do
for arch in amd64 arm64; do
upload_url="${{ github.event.release.upload_url }}"
upload_url=${upload_url%%\{*\}}
file=bin/clm-$os-$arch
echo "Uploading $file to $upload_url ..."
curl -sSf \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
-H "Content-Type: $(file -b --mime-type $file)" \
--data-binary @$file \
"$upload_url?name=$(basename $file)"
done
done
8 changes: 4 additions & 4 deletions .github/workflows/publish-scaffold.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Publish scaffolder
name: Publish scaffold

on:
release:
Expand Down Expand Up @@ -29,9 +29,9 @@ jobs:
file=bin/scaffold-$os-$arch
echo "Building $file ..."
LDFLAGS=""
LDFLAGS+=" -X github.com/sap/component-operator-runtime/internal/version.version=${{ github.event.release.tag_name }}"
LDFLAGS+=" -X github.com/sap/component-operator-runtime/internal/version.gitCommit=${{ github.sha }}"
LDFLAGS+=" -X github.com/sap/component-operator-runtime/internal/version.gitTreeState=clean"
LDFLAGS+=" -X \"github.com/sap/component-operator-runtime/internal/version.version=${{ github.event.release.tag_name }}\""
LDFLAGS+=" -X \"github.com/sap/component-operator-runtime/internal/version.gitCommit=${{ github.sha }}\""
LDFLAGS+=" -X \"github.com/sap/component-operator-runtime/internal/version.gitTreeState=clean\""
GOOS=$os GOARCH=$arch go build -o $file -ldflags "$LDFLAGS" ./scaffold
done
done
Expand Down
31 changes: 30 additions & 1 deletion .github/workflows/run-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ jobs:

- name: Build scaffold
run: |
go build -o bin/scaffold -ldflags "-X \"main.version=$(pwd)\"" ./scaffold
LDFLAGS=""
LDFLAGS+=" -X \"github.com/sap/component-operator-runtime/internal/version.version=$(pwd)\""
LDFLAGS+=" -X \"github.com/sap/component-operator-runtime/internal/version.gitCommit=${{ github.sha }}\""
LDFLAGS+=" -X \"github.com/sap/component-operator-runtime/internal/version.gitTreeState=clean\""
go build -o bin/scaffold -ldflags "$LDFLAGS" ./scaffold
echo "Running 'scaffold --version' ..."
bin/scaffold --version

Expand Down Expand Up @@ -141,3 +145,28 @@ jobs:
# run: |
# cd $RUNNER_TEMP/src
# make docker-build

test-clm:
runs-on: ubuntu-24.04
needs:
- check-generate
- unit-and-integration-tests

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup go
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'

- name: Build clm
run: |
LDFLAGS=""
LDFLAGS+=" -X \"github.com/sap/component-operator-runtime/internal/version.version=$(pwd)\""
LDFLAGS+=" -X \"github.com/sap/component-operator-runtime/internal/version.gitCommit=${{ github.sha }}\""
LDFLAGS+=" -X \"github.com/sap/component-operator-runtime/internal/version.gitTreeState=clean\""
go build -o bin/clm -ldflags "$LDFLAGS" ./clm
echo "Running 'clm version -o json' ..."
bin/clm version -o json
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ __debug_bin
*.swo
*~
.DS_Store
.vscode

# temp stuff
/tmp
Expand Down
26 changes: 26 additions & 0 deletions clm/clm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and component-operator-runtime contributors
SPDX-License-Identifier: Apache-2.0
*/

package main

import (
"os"

"github.com/go-logr/logr"

"sigs.k8s.io/controller-runtime/pkg/log"

"github.com/sap/component-operator-runtime/clm/cmd"
)

func main() {
// ctx, _ := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)

log.SetLogger(logr.Discard())

if err := cmd.Execute(); err != nil {
os.Exit(1)
}
}
151 changes: 151 additions & 0 deletions clm/cmd/apply.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and component-operator-runtime contributors
SPDX-License-Identifier: Apache-2.0
*/

package cmd

import (
"context"
"fmt"
"time"

"github.com/spf13/cobra"

apierrors "k8s.io/apimachinery/pkg/api/errors"
utilerrors "k8s.io/apimachinery/pkg/util/errors"

"github.com/sap/component-operator-runtime/clm/internal/backoff"
"github.com/sap/component-operator-runtime/clm/internal/manifests"
"github.com/sap/component-operator-runtime/clm/internal/release"
"github.com/sap/component-operator-runtime/pkg/component"
"github.com/sap/component-operator-runtime/pkg/reconciler"
"github.com/sap/go-generics/slices"
)

const applyUsage = `Apply component manifests to Kubernetes cluster`

type applyOptions struct {
valuesSources []string
timeout time.Duration
}

func newApplyCmd() *cobra.Command {
options := &applyOptions{}

cmd := &cobra.Command{
Use: "apply NAME SOURCE...",
Short: "Apply component",
Long: applyUsage,
SilenceUsage: true,
Args: cobra.MinimumNArgs(2),
PreRunE: func(c *cobra.Command, args []string) error {
return nil
},
RunE: func(c *cobra.Command, args []string) (err error) {
name := args[0]
manifestSources := args[1:]
namespace := c.Flag("namespace").Value.String()

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

reconciler := reconciler.NewReconciler(fullName, clnt, reconciler.ReconcilerOptions{
UpdatePolicy: ref(reconciler.UpdatePolicySsaOverride),
})

releaseClient := release.NewClient(fullName, clnt)

ownerId := fullName + "/" + namespace + "/" + name

objects, err := manifests.Generate(manifestSources, options.valuesSources, fullName, clnt, namespace, name)
if err != nil {
return err
}

release, err := releaseClient.Get(context.TODO(), namespace, name)
if err != nil {
if apierrors.IsNotFound(err) {
release, err = releaseClient.Create(context.TODO(), namespace, name)
if err != nil {
return err
}
} else {
return err
}
}

if release.IsDeleting() {
return fmt.Errorf("release %s/%s is being deleted; updates are not allowed in this state", release.GetNamespace(), release.GetName())
}

release.Revision += 1

backoff := backoff.New()

var timeout <-chan time.Time
if options.timeout > 0 {
timeout = time.After(options.timeout)
}

defer func() {
if err != nil {
release.State = component.StateError
}
if updateErr := releaseClient.Update(context.TODO(), release); updateErr != nil {
err = utilerrors.NewAggregate([]error{err, updateErr})
}
}()

for {
release.State = component.StateProcessing
ok, err := reconciler.Apply(context.TODO(), &release.Inventory, objects, namespace, ownerId, release.Revision)
if err != nil {
return err
}
if ok {
release.State = component.StateReady
break
}
if err := releaseClient.Update(context.TODO(), release); err != nil {
return err
}
select {
case <-time.After(backoff.Next()):
case <-timeout:
return fmt.Errorf("timeout applying release %s/%s", release.GetNamespace(), release.GetName())
}
}

fmt.Printf("Release %s/%s successfully applied\n", release.GetNamespace(), release.GetName())

return nil
},
ValidArgsFunction: func(c *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) > 0 {
return nil, cobra.ShellCompDirectiveDefault
}
if clnt, err := getClient(c.Flag("kubeconfig").Value.String()); err == nil {
releaseClient := release.NewClient(fullName, clnt)
namespace := c.Flag("namespace").Value.String()
if namespace == "" {
namespace = "default"
}
ctx, cancel := context.WithTimeout(context.TODO(), 3*time.Second)
defer cancel()
if releases, err := releaseClient.List(ctx, namespace); err == nil {
return slices.Collect(releases, func(release *release.Release) string { return release.GetName() }), cobra.ShellCompDirectiveNoFileComp
}
}
return nil, cobra.ShellCompDirectiveDefault
},
}

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.DurationVar(&options.timeout, "timeout", 0, "Time to wait for the operation to complete (default is to wait forever)")

return cmd
}
Loading