Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add versions - apprepository-controller #3449

Merged
merged 2 commits into from
Sep 21, 2021
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
5 changes: 3 additions & 2 deletions cmd/apprepository-controller/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ WORKDIR /go/src/github.com/kubeapps/kubeapps
COPY go.mod go.sum ./
COPY pkg pkg
COPY cmd cmd
ARG VERSION
# With the trick below, Go's build cache is kept between builds.
# https://github.com/golang/go/issues/27719#issuecomment-514747274
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 go build -installsuffix cgo ./cmd/apprepository-controller
--mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 go build -installsuffix cgo -ldflags "-X github.com/kubeapps/kubeapps/cmd/apprepository-controller/cmd.version=$VERSION" ./cmd/apprepository-controller

FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
Expand Down
127 changes: 127 additions & 0 deletions cmd/apprepository-controller/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
Copyright 2021 VMware. All Rights Reserved.

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 cmd

import (
"fmt"
"os"

"github.com/kubeapps/kubeapps/cmd/apprepository-controller/server"
"github.com/spf13/cobra"
"github.com/spf13/viper"

corev1 "k8s.io/api/core/v1"
log "k8s.io/klog/v2"
)

var (
cfgFile string
serveOpts server.Config
// This Version var is updated during the build
// see the -ldflags option in the cmd/apprepository-controller/Dockerfile
version = "devel"
)

// rootCmd represents the base command when called without any subcommands
var rootCmd *cobra.Command

func newRootCmd() *cobra.Command {
return &cobra.Command{
Use: "apprepository-controller",
Short: "Apprepository-controller is a Kubernetes controller for managing package repositories added to Kubeapps.",
PreRun: func(cmd *cobra.Command, args []string) {
log.Infof("apprepository-controller has been configured with: %#v", serveOpts)
},
RunE: func(cmd *cobra.Command, args []string) error {

return server.Serve(serveOpts)
},
Version: "devel",
}
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
cobra.CheckErr(rootCmd.Execute())
}

func init() {
cobra.OnInitialize(initConfig)
rootCmd = newRootCmd()
rootCmd.SetVersionTemplate(version)
setFlags(rootCmd)
serveOpts.ImagePullSecretsRefs = getImagePullSecretsRefs(serveOpts.RepoSyncImagePullSecrets)
}

func setFlags(c *cobra.Command) {
c.Flags().StringVar(&serveOpts.Kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
c.Flags().StringVar(&serveOpts.MasterURL, "master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.")
c.Flags().StringVar(&serveOpts.RepoSyncImage, "repo-sync-image", "docker.io/kubeapps/asset-syncer:latest", "container repo/image to use in CronJobs")
c.Flags().StringSliceVar(&serveOpts.RepoSyncImagePullSecrets, "repo-sync-image-pullsecrets", nil, "optional reference to secrets in the same namespace to use for pulling the image used by this pod")
c.Flags().StringVar(&serveOpts.RepoSyncCommand, "repo-sync-cmd", "/chart-repo", "command used to sync/delete repos for repo-sync-image")
c.Flags().StringVar(&serveOpts.KubeappsNamespace, "namespace", "kubeapps", "Namespace to discover AppRepository resources")
c.Flags().BoolVar(&serveOpts.ReposPerNamespace, "repos-per-namespace", true, "Defaults to watch for repos in all namespaces. Switch to false to watch only the configured namespace.")
c.Flags().StringVar(&serveOpts.DBURL, "database-url", "localhost", "Database URL")
c.Flags().StringVar(&serveOpts.DBUser, "database-user", "root", "Database user")
c.Flags().StringVar(&serveOpts.DBName, "database-name", "charts", "Database name")
c.Flags().StringVar(&serveOpts.DBSecretName, "database-secret-name", "kubeapps-db", "Kubernetes secret name for database credentials")
c.Flags().StringVar(&serveOpts.DBSecretKey, "database-secret-key", "postgresql-root-password", "Kubernetes secret key used for database credentials")
c.Flags().StringVar(&serveOpts.UserAgentComment, "user-agent-comment", "", "UserAgent comment used during outbound requests")
c.Flags().StringVar(&serveOpts.Crontab, "crontab", "*/10 * * * *", "CronTab to specify schedule")
// TTLSecondsAfterFinished specifies the number of seconds a sync job should live after finishing.
// The support for this is currently beta in K8s (v1.21), older versions require a feature gate being set to enable it.
// See https://kubernetes.io/docs/concepts/workloads/controllers/job/#clean-up-finished-jobs-automatically
c.Flags().StringVar(&serveOpts.TTLSecondsAfterFinished, "ttl-lifetime-afterfinished-job", "3600", "Lifetime limit after which the resource Jobs are deleted expressed in seconds by default is 3600 (1h) ")

}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := os.UserHomeDir()
cobra.CheckErr(err)

// Search config in home directory with name ".kubeops" (without extension).
viper.AddConfigPath(home)
viper.SetConfigType("yaml")
viper.SetConfigName(".kubeops")
}

viper.AutomaticEnv() // read in environment variables that match

// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
}
}

// getImagePullSecretsRefs gets the []string of Secrets names from the
// StringSliceVar flag list passed in the repoSyncImagePullSecrets arg
func getImagePullSecretsRefs(imagePullSecretsRefsArr []string) []corev1.LocalObjectReference {
var imagePullSecretsRefs []corev1.LocalObjectReference

// getting and appending a []LocalObjectReference for each ImagePullSecret passed
for _, imagePullSecretName := range imagePullSecretsRefsArr {
imagePullSecretsRefs = append(imagePullSecretsRefs, corev1.LocalObjectReference{Name: imagePullSecretName})
}
return imagePullSecretsRefs
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,45 @@
package main
/*
Copyright 2021 VMware. All Rights Reserved.

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 cmd

import (
"bytes"
"strings"

"testing"

"github.com/google/go-cmp/cmp"
"github.com/kubeapps/kubeapps/cmd/apprepository-controller/server"
v1 "k8s.io/api/core/v1"
)

func TestParseFlagsCorrect(t *testing.T) {
var tests = []struct {
name string
args []string
conf Config
conf server.Config
}{
{
"no arguments returns default flag values",
[]string{},
Config{
server.Config{
Kubeconfig: "",
MasterURL: "",
RepoSyncImage: "quay.io/helmpack/chart-repo:latest",
RepoSyncImage: "docker.io/kubeapps/asset-syncer:latest",
RepoSyncImagePullSecrets: nil,
RepoSyncCommand: "/chart-repo",
KubeappsNamespace: "kubeapps",
Expand All @@ -33,7 +52,6 @@ func TestParseFlagsCorrect(t *testing.T) {
UserAgentComment: "",
Crontab: "*/10 * * * *",
TTLSecondsAfterFinished: "3600",
Args: []string{},
},
},
{
Expand All @@ -42,10 +60,10 @@ func TestParseFlagsCorrect(t *testing.T) {
"--repo-sync-image-pullsecrets=s1, s2",
"--repo-sync-image-pullsecrets= s3",
},
Config{
server.Config{
Kubeconfig: "",
MasterURL: "",
RepoSyncImage: "quay.io/helmpack/chart-repo:latest",
RepoSyncImage: "docker.io/kubeapps/asset-syncer:latest",
RepoSyncImagePullSecrets: []string{"s1", " s2", " s3"},
ImagePullSecretsRefs: []v1.LocalObjectReference{{Name: "s1"}, {Name: " s2"}, {Name: " s3"}},
RepoSyncCommand: "/chart-repo",
Expand All @@ -59,7 +77,6 @@ func TestParseFlagsCorrect(t *testing.T) {
UserAgentComment: "",
Crontab: "*/10 * * * *",
TTLSecondsAfterFinished: "3600",
Args: []string{},
},
},
{
Expand All @@ -81,7 +98,7 @@ func TestParseFlagsCorrect(t *testing.T) {
"--user-agent-comment", "foo11",
"--crontab", "foo12",
},
Config{
server.Config{
Kubeconfig: "foo01",
MasterURL: "foo02",
RepoSyncImage: "foo03",
Expand All @@ -98,23 +115,21 @@ func TestParseFlagsCorrect(t *testing.T) {
UserAgentComment: "foo11",
Crontab: "foo12",
TTLSecondsAfterFinished: "3600",
Args: []string{},
},
},
}

for _, tt := range tests {
t.Run(strings.Join(tt.args, " "), func(t *testing.T) {
conf, output, err := parseFlags("program", tt.args)
conf.ImagePullSecretsRefs = getImagePullSecretsRefs(conf.RepoSyncImagePullSecrets)

if err != nil {
t.Errorf("err got:\n%v\nwant nil", err)
}
if output != "" {
t.Errorf("output got:\n%q\nwant empty", output)
}
if got, want := *conf, tt.conf; !cmp.Equal(want, got) {
t.Run(tt.name, func(t *testing.T) {
cmd := newRootCmd()
b := bytes.NewBufferString("")
cmd.SetOut(b)
cmd.SetErr(b)
setFlags(cmd)
cmd.SetArgs(tt.args)
cmd.Execute()
serveOpts.ImagePullSecretsRefs = getImagePullSecretsRefs(serveOpts.RepoSyncImagePullSecrets)
if got, want := serveOpts, tt.conf; !cmp.Equal(want, got) {
t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(want, got))
}
})
Expand All @@ -140,12 +155,15 @@ func TestParseFlagsError(t *testing.T) {
}

for _, tt := range tests {
t.Run(strings.Join(tt.args, " "), func(t *testing.T) {
conf, _, err := parseFlags("prog", tt.args)
if conf != nil {
t.Errorf("conf got %v, want nil", conf)
}
if strings.Index(err.Error(), tt.errstr) < 0 {
t.Run(tt.name, func(t *testing.T) {
cmd := newRootCmd()
b := bytes.NewBufferString("")
cmd.SetOut(b)
cmd.SetErr(b)
setFlags(cmd)
cmd.SetArgs(tt.args)
err := cmd.Execute()
if !strings.Contains(err.Error(), tt.errstr) {
t.Errorf("err got %q, want to find %q", err.Error(), tt.errstr)
}
})
Expand Down
3 changes: 1 addition & 2 deletions cmd/apprepository-controller/hack/custom-boilerplate.go.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright YEAR Bitnami.
Copyright 2021 VMware. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -13,4 +13,3 @@ 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.
*/

Loading