diff --git a/go.mod b/go.mod index b0e51ca..ab77a4b 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/moby/term v0.0.0-20221205130635-1aeaba878587 github.com/urfave/cli/v2 v2.25.0 gopkg.in/yaml.v2 v2.4.0 + gotest.tools/v3 v3.0.3 k8s.io/api v0.27.1 k8s.io/apimachinery v0.27.1 k8s.io/client-go v0.27.1 diff --git a/go.sum b/go.sum index 92c81c3..fb66ea9 100644 --- a/go.sum +++ b/go.sum @@ -252,6 +252,7 @@ github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs github.com/skeema/knownhosts v1.1.1 h1:MTk78x9FPgDFVFkDLTrsnnfCJl7g1C/nnKvePgrIngE= github.com/skeema/knownhosts v1.1.1/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -402,6 +403,7 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -470,6 +472,7 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/api v0.27.1 h1:Z6zUGQ1Vd10tJ+gHcNNNgkV5emCyW+v2XTmn+CLjSd0= diff --git a/src/cli/deploy.go b/src/cli/deploy.go index 134ad05..f1639f1 100644 --- a/src/cli/deploy.go +++ b/src/cli/deploy.go @@ -1,6 +1,7 @@ package cli import ( + "github.com/nearform/initium-cli/src/services/git" knative "github.com/nearform/initium-cli/src/services/k8s" "github.com/urfave/cli/v2" ) @@ -20,7 +21,12 @@ func (c *icli) Deploy(cCtx *cli.Context) error { return err } - return knative.Apply(cCtx.String(namespaceFlag), config, project, c.dockerImage) + commitSha, err := git.GetHash() + if err != nil { + return err + } + + return knative.Apply(cCtx.String(namespaceFlag), commitSha, config, project, c.dockerImage) } func (c icli) DeployCMD() *cli.Command { diff --git a/src/services/k8s/knative.go b/src/services/k8s/knative.go index 744dd6f..6e4c3c1 100644 --- a/src/services/k8s/knative.go +++ b/src/services/k8s/knative.go @@ -23,6 +23,11 @@ import ( servingv1client "knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1" ) +const ( + UpdateShaAnnotationName = "initium.nearform.com/updateSha" + UpdateTimestampAnnotationName = "initium.nearform.com/updateTimestamp" +) + func Config(endpoint string, token string, caCrt []byte) (*rest.Config, error) { if _, err := certutil.NewPoolFromBytes(caCrt); err != nil { return nil, fmt.Errorf("Expected to load root CA from bytes, but got err: %v", err) @@ -37,7 +42,7 @@ func Config(endpoint string, token string, caCrt []byte) (*rest.Config, error) { }, nil } -func loadManifest(project *project.Project, dockerImage docker.DockerImage) (*servingv1.Service, error) { +func loadManifest(namespace string, commitSha string, project *project.Project, dockerImage docker.DockerImage) (*servingv1.Service, error) { knativeTemplate := path.Join("assets", "knative", "service.yaml.tmpl") template, err := template.ParseFS(project.Resources, knativeTemplate) if err != nil { @@ -68,15 +73,22 @@ func loadManifest(project *project.Project, dockerImage docker.DockerImage) (*se return nil, fmt.Errorf("decoded object is not a Knative Service: %v", obj) } + service.ObjectMeta.Namespace = namespace + service.ObjectMeta.Name = project.Name + service.Spec.Template.ObjectMeta.Annotations = map[string]string{ + UpdateShaAnnotationName: commitSha, + UpdateTimestampAnnotationName: time.Now().Format(time.RFC3339), + } + return service, nil } -func Apply(namespace string, config *rest.Config, project *project.Project, dockerImage docker.DockerImage) error { +func Apply(namespace string, commitSha string, config *rest.Config, project *project.Project, dockerImage docker.DockerImage) error { log.Info("Deploying Knative service", "host", config.Host, "name", project.Name, "namespace", namespace) ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5) defer cancel() - serviceManifest, err := loadManifest(project, dockerImage) + serviceManifest, err := loadManifest(namespace, commitSha, project, dockerImage) if err != nil { return err } @@ -87,9 +99,6 @@ func Apply(namespace string, config *rest.Config, project *project.Project, dock return fmt.Errorf("Error creating the knative client %v", err) } - serviceManifest.ObjectMeta.Namespace = namespace - serviceManifest.ObjectMeta.Name = project.Name - client, err := kubernetes.NewForConfig(config) if err != nil { return fmt.Errorf("Creating Kubernetes client %v", err) diff --git a/src/services/k8s/knative_test.go b/src/services/k8s/knative_test.go index 8ba5320..5118c9d 100644 --- a/src/services/k8s/knative_test.go +++ b/src/services/k8s/knative_test.go @@ -3,6 +3,7 @@ package k8s import ( "encoding/base64" "fmt" + "gotest.tools/v3/assert" "os" "path" "testing" @@ -54,22 +55,28 @@ func TestConfig(t *testing.T) { } func TestLoadManifest(t *testing.T) { - proj_knative := &project.Project{Name: "knative_test", + namespace := "custom" + commitSha := "93f4be93" + + proj := &project.Project{Name: "knative_test", Directory: path.Join(root, "example"), Resources: os.DirFS(root), } - docker_image := docker.DockerImage{ + dockerImage := docker.DockerImage{ Registry: "example.com", Directory: ".", Name: "test", Tag: "v1.1.0", } - _, err := loadManifest(proj_knative, docker_image) + serviceManifest, err := loadManifest(namespace, commitSha, proj, dockerImage) if err != nil { t.Fatalf(fmt.Sprintf("Error: %v", err)) } + annotations := serviceManifest.Spec.Template.ObjectMeta.Annotations + assert.Assert(t, annotations[UpdateTimestampAnnotationName] != "", "Missing %s annotation", UpdateTimestampAnnotationName) + assert.Assert(t, annotations[UpdateShaAnnotationName] == commitSha, "Expected %s SHA, got %s", commitSha, annotations[UpdateShaAnnotationName]) }