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

Detect different versions of cert-manager #1546

Merged
merged 9 commits into from Jun 4, 2020
3 changes: 2 additions & 1 deletion pkg/engine/health/health.go
Expand Up @@ -15,6 +15,7 @@ import (

kudov1beta1 "github.com/kudobuilder/kudo/pkg/apis/kudo/v1beta1"
"github.com/kudobuilder/kudo/pkg/engine"
"github.com/kudobuilder/kudo/pkg/kudoctl/clog"
)

func isJobTerminallyFailed(job *batchv1.Job) (bool, string) {
Expand Down Expand Up @@ -61,7 +62,7 @@ func IsHealthy(obj runtime.Object) error {
log.Printf("HealthUtil: Deployment %v is NOT healthy. %s", obj.Name, msg)
return errors.New(msg)
}
log.Printf("Deployment %v is marked healthy\n", obj.Name)
clog.V(2).Printf("Deployment %v is marked healthy\n", obj.Name)
return nil
case *batchv1.Job:

Expand Down
74 changes: 39 additions & 35 deletions pkg/kudoctl/cmd/init.go
Expand Up @@ -60,6 +60,7 @@ and finishes with success if KUDO is already installed.

type initCmd struct {
out io.Writer
errOut io.Writer
fs afero.Fs
image string
imagePullPolicy string
Expand All @@ -77,8 +78,8 @@ type initCmd struct {
selfSignedWebhookCA bool
}

func newInitCmd(fs afero.Fs, out io.Writer) *cobra.Command {
i := &initCmd{fs: fs, out: out}
func newInitCmd(fs afero.Fs, out io.Writer, errOut io.Writer, client *kube.Client) *cobra.Command {
i := &initCmd{fs: fs, out: out, errOut: errOut, client: client}

cmd := &cobra.Command{
Use: "init",
Expand Down Expand Up @@ -154,47 +155,50 @@ func (initCmd *initCmd) run() error {
}
}

//TODO: implement output=yaml|json (define a type for output to constrain)
//define an Encoder to replace YAMLWriter
if strings.ToLower(initCmd.output) == "yaml" {
manifests, err := setup.AsYamlManifests(opts, initCmd.crdOnly)
if err != nil {
return err
}
if err := initCmd.YAMLWriter(initCmd.out, manifests); err != nil {
return err
}
}

if initCmd.dryRun {
return nil
}
installer := setup.NewInstaller(opts, initCmd.crdOnly)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't know why crdOnly is not part of the opts. But that's another story


// initialize client
if err := initCmd.initialize(); err != nil {
return clog.Errorf("error initializing: %s", err)
if !initCmd.dryRun {
if err := initCmd.initialize(); err != nil {
return clog.Errorf("error initializing: %s", err)
}
}
clog.Printf("$KUDO_HOME has been configured at %s", Settings.Home)
if initCmd.clientOnly {
return nil
}

// initialize server
if !initCmd.clientOnly {
clog.V(4).Printf("initializing server")
if initCmd.client == nil {
client, err := kube.GetKubeClient(Settings.KubeConfig)
if err != nil {
return clog.Errorf("could not get Kubernetes client: %s", err)
}
initCmd.client = client
clog.V(4).Printf("initializing server")
if initCmd.client == nil {
client, err := kube.GetKubeClient(Settings.KubeConfig)
if err != nil {
return clog.Errorf("could not get Kubernetes client: %s", err)
}
ok, err := initCmd.preInstallVerify(opts)
initCmd.client = client
}
ok, err := initCmd.preInstallVerify(installer)
if err != nil {
return err
}
if !ok {
return fmt.Errorf("failed to verify installation requirements")
}

//TODO: implement output=yaml|json (define a type for output to constrain)
//define an Encoder to replace YAMLWriter
if strings.ToLower(initCmd.output) == "yaml" {
manifests, err := installer.AsYamlManifests()
if err != nil {
return err
}
if !ok {
return fmt.Errorf("failed to verify installation requirements")
if err := initCmd.YAMLWriter(initCmd.out, manifests); err != nil {
return err
}
}

if err := setup.Install(initCmd.client, opts, initCmd.crdOnly); err != nil {
if !initCmd.dryRun {
if err := installer.Install(initCmd.client); err != nil {
return clog.Errorf("error installing: %s", err)
}

Expand All @@ -211,14 +215,14 @@ func (initCmd *initCmd) run() error {
}

// preInstallVerify runs the pre-installation verification and returns true if the installation can continue
func (initCmd *initCmd) preInstallVerify(opts kudoinit.Options) (bool, error) {
func (initCmd *initCmd) preInstallVerify(v kudoinit.InstallVerifier) (bool, error) {
result := verifier.NewResult()
if err := setup.PreInstallVerify(initCmd.client, opts, initCmd.crdOnly, &result); err != nil {
if err := v.PreInstallVerify(initCmd.client, &result); err != nil {
return false, err
}
result.PrintWarnings(initCmd.out)
result.PrintWarnings(initCmd.errOut)
if !result.IsValid() {
result.PrintErrors(initCmd.out)
result.PrintErrors(initCmd.errOut)
return false, nil
}
return true, nil
Expand Down
12 changes: 10 additions & 2 deletions pkg/kudoctl/cmd/init_integration_test.go
Expand Up @@ -104,8 +104,10 @@ func TestIntegInitForCRDs(t *testing.T) {
crds := crd.NewInitializer().Resources()

var buf bytes.Buffer
var errBuf bytes.Buffer
cmd := &initCmd{
out: &buf,
errOut: &errBuf,
fs: afero.NewMemMapFs(),
client: kclient,
crdOnly: true,
Expand Down Expand Up @@ -146,8 +148,10 @@ func TestIntegInitWithNameSpace(t *testing.T) {
crds := crd.NewInitializer().Resources()

var buf bytes.Buffer
var errBuf bytes.Buffer
cmd := &initCmd{
out: &buf,
errOut: &errBuf,
fs: afero.NewMemMapFs(),
client: kclient,
ns: namespace,
Expand All @@ -158,7 +162,7 @@ func TestIntegInitWithNameSpace(t *testing.T) {
err = cmd.run()
require.Error(t, err)
assert.Equal(t, "failed to verify installation requirements", err.Error())
assertStringContains(t, "Namespace integration-test does not exist - KUDO expects that any namespace except the default kudo-system is created beforehand", buf.String())
assertStringContains(t, "Namespace integration-test does not exist - KUDO expects that any namespace except the default kudo-system is created beforehand", errBuf.String())

// Then we manually create the namespace.
ns := testutils.NewResource("v1", "Namespace", namespace, "")
Expand Down Expand Up @@ -269,8 +273,10 @@ func TestInitWithServiceAccount(t *testing.T) {
crds := crd.NewInitializer().Resources()

var buf bytes.Buffer
var errBuf bytes.Buffer
cmd := &initCmd{
out: &buf,
errOut: &errBuf,
fs: afero.NewMemMapFs(),
client: kclient,
ns: namespace,
Expand Down Expand Up @@ -309,7 +315,7 @@ func TestInitWithServiceAccount(t *testing.T) {
if tt.errMessageContains != "" {
require.Error(t, err)
assert.Equal(t, "failed to verify installation requirements", err.Error())
assertStringContains(t, tt.errMessageContains, buf.String())
assertStringContains(t, tt.errMessageContains, errBuf.String())
} else {
assert.NoError(t, err)
defer func() {
Expand Down Expand Up @@ -355,8 +361,10 @@ func TestNoErrorOnReInit(t *testing.T) {
clog.InitNoFlag(&buf, clog.Level(4))
defer func() { clog.InitNoFlag(&buf, clog.Level(0)) }()

var errBuf bytes.Buffer
cmd := &initCmd{
out: &buf,
errOut: &errBuf,
fs: afero.NewMemMapFs(),
client: kclient,
crdOnly: true,
Expand Down
103 changes: 94 additions & 9 deletions pkg/kudoctl/cmd/init_test.go
Expand Up @@ -11,8 +11,11 @@ import (

"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"github.com/thoas/go-funk"
v1 "k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
rbacv1 "k8s.io/api/rbac/v1"
extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextfake "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/fake"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -82,24 +85,36 @@ func TestInitCmd_exists(t *testing.T) {

// TestInitCmd_output tests that init -o can be decoded
func TestInitCmd_output(t *testing.T) {

fc := fake.NewSimpleClientset()
client := &kube.Client{
KubeClient: fc,
ExtClient: apiextfake.NewSimpleClientset(),
}

MockCRD(client, "certificates.cert-manager.io", "v1alpha2")
MockCRD(client, "issuers.cert-manager.io", "v1alpha2")

tests := []string{"yaml"}
for _, s := range tests {
var buf bytes.Buffer
var errOut bytes.Buffer
cmd := &initCmd{
out: &buf,
client: &kube.Client{KubeClient: fc},
errOut: &errOut,
client: client,
output: s,
dryRun: true,
}
// ensure that we can marshal
if err := cmd.run(); err != nil {
t.Fatal(err)
}
// ensure no calls against the server
if got := len(fc.Actions()); got != 0 {
t.Errorf("expected no server calls, got %d", got)
// ensure no modifying calls against the server
forbiddenVerbs := []string{"create", "update", "patch", "delete"}
for _, a := range fc.Actions() {
if funk.Contains(forbiddenVerbs, a.GetVerb()) {
t.Errorf("got modifying server call: %v", a)
}
}

assert.True(t, len(buf.Bytes()) > 0, "Buffer needs to have an output")
Expand All @@ -119,6 +134,44 @@ func TestInitCmd_output(t *testing.T) {
}

func TestInitCmd_yamlOutput(t *testing.T) {
customNs := &v1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
},
}
customSa := &v1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Namespace: "foo",
Name: "safoo",
},
}
crb := &rbacv1.ClusterRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "safoocrb",
},
Subjects: []rbacv1.Subject{
{
Kind: "ServiceAccount",
Namespace: "foo",
Name: "safoo",
},
},
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "ClusterRole",
Name: "cluster-admin",
},
}

fc := fake.NewSimpleClientset(crb, customNs, customSa)
client := &kube.Client{
KubeClient: fc,
ExtClient: apiextfake.NewSimpleClientset(),
}

MockCRD(client, "certificates.cert-manager.io", "v1alpha2")
MockCRD(client, "issuers.cert-manager.io", "v1alpha2")

tests := []struct {
name string
goldenFile string
Expand All @@ -127,13 +180,14 @@ func TestInitCmd_yamlOutput(t *testing.T) {
{"custom namespace", "deploy-kudo-ns.yaml", map[string]string{"dry-run": "true", "output": "yaml", "namespace": "foo"}},
{"yaml output", "deploy-kudo.yaml", map[string]string{"dry-run": "true", "output": "yaml"}},
{"service account", "deploy-kudo-sa.yaml", map[string]string{"dry-run": "true", "output": "yaml", "service-account": "safoo", "namespace": "foo"}},
{"using default cert-manager", "deploy-kudo-webhook.yaml", map[string]string{"dry-run": "true", "output": "yaml"}},
}

for _, tt := range tests {
fs := afero.NewMemMapFs()
out := &bytes.Buffer{}
initCmd := newInitCmd(fs, out)
errOut := &bytes.Buffer{}
initCmd := newInitCmd(fs, out, errOut, client)

Settings.AddFlags(initCmd.Flags())

for f, value := range tt.flags {
Expand All @@ -143,7 +197,7 @@ func TestInitCmd_yamlOutput(t *testing.T) {
}

if err := initCmd.RunE(initCmd, []string{}); err != nil {
t.Fatal(err)
t.Fatal(err, errOut.String())
}

gp := filepath.Join("testdata", tt.goldenFile+".golden")
Expand Down Expand Up @@ -183,7 +237,8 @@ func TestNewInitCmd(t *testing.T) {

t.Run(tt.name, func(t *testing.T) {
out := &bytes.Buffer{}
initCmd := newInitCmd(fs, out)
errOut := &bytes.Buffer{}
initCmd := newInitCmd(fs, out, errOut, nil)
for key, value := range tt.flags {
if err := initCmd.Flags().Set(key, value); err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -236,3 +291,33 @@ func TestClientInitialize(t *testing.T) {
}
assert.Equal(t, r.CurrentConfiguration().URL, RepositoryURL)
}

func MockCRD(client *kube.Client, crdName string, apiVersion string) {
client.ExtClient.(*apiextfake.Clientset).Fake.PrependReactor("get", "customresourcedefinitions", func(action testcore.Action) (handled bool, ret runtime.Object, err error) {

getAction, _ := action.(testcore.GetAction)
if getAction != nil {
if getAction.GetName() == crdName {
crd := &extv1.CustomResourceDefinition{
TypeMeta: metav1.TypeMeta{
APIVersion: apiVersion,
},
ObjectMeta: metav1.ObjectMeta{
Name: crdName,
},
Spec: extv1.CustomResourceDefinitionSpec{
Versions: []extv1.CustomResourceDefinitionVersion{
{
Name: apiVersion,
},
},
},
Status: extv1.CustomResourceDefinitionStatus{},
}
return true, crd, nil
}
}

return false, nil, nil
})
}
6 changes: 4 additions & 2 deletions pkg/kudoctl/cmd/repo_add_test.go
Expand Up @@ -38,13 +38,14 @@ func TestAddBadURLRepo(t *testing.T) {
// setup
fs := afero.NewMemMapFs()
out := &bytes.Buffer{}
errOut := &bytes.Buffer{}

home := kudohome.Home("kudo_home")
err := fs.Mkdir(home.String(), 0755)
if err != nil {
t.Fatal(err)
}
i := &initCmd{fs: fs, out: out, home: home}
i := &initCmd{fs: fs, out: out, errOut: errOut, home: home}
if err := i.initialize(); err != nil {
t.Error(err)
}
Expand All @@ -60,13 +61,14 @@ func TestAddSkipCheck(t *testing.T) {
// setup
fs := afero.NewMemMapFs()
out := &bytes.Buffer{}
errOut := &bytes.Buffer{}

home := kudohome.Home("kudo_home")
err := fs.Mkdir(home.String(), 0755)
if err != nil {
t.Fatal(err)
}
i := &initCmd{fs: fs, out: out, home: home}
i := &initCmd{fs: fs, out: out, errOut: errOut, home: home}
if err := i.initialize(); err != nil {
t.Error(err)
}
Expand Down