Skip to content

Commit

Permalink
Detect different versions of cert-manager (#1546)
Browse files Browse the repository at this point in the history
Co-authored-by: Ken Sipe <kensipe@gmail.com>
Signed-off-by: Andreas Neumann <aneumann@mesosphere.com>
  • Loading branch information
ANeumann82 and kensipe committed Jun 4, 2020
1 parent 2464231 commit f8d96bd
Show file tree
Hide file tree
Showing 13 changed files with 346 additions and 870 deletions.
3 changes: 2 additions & 1 deletion pkg/engine/health/health.go
Original file line number Diff line number Diff line change
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
76 changes: 42 additions & 34 deletions pkg/kudoctl/cmd/init.go
Original file line number Diff line number Diff line change
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,54 @@ 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
installer := setup.NewInstaller(opts, initCmd.crdOnly)

// initialize client
if !initCmd.dryRun {
if err := initCmd.initialize(); err != nil {
return clog.Errorf("error initializing: %s", err)
}
}

if initCmd.dryRun {
return nil
// if output is yaml | json, we only print the requested output style.
if initCmd.output == "" {
clog.Printf("$KUDO_HOME has been configured at %s", Settings.Home)
}

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

// 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 +219,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
Original file line number Diff line number Diff line change
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
121 changes: 94 additions & 27 deletions pkg/kudoctl/cmd/init_test.go
Original file line number Diff line number Diff line change
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 All @@ -29,24 +32,6 @@ import (

var updateGolden = flag.Bool("update", false, "update .golden files and manifests in /config/crd")

func TestInitCmd_dry(t *testing.T) {

var buf bytes.Buffer

cmd := &initCmd{
out: &buf,
fs: afero.NewMemMapFs(),
dryRun: true,
}
if err := cmd.run(); err != nil {
t.Errorf("expected error: %v", err)
}
expected := ""
if !strings.Contains(buf.String(), expected) {
t.Errorf("expected %q, got %q", expected, buf.String())
}
}

func TestInitCmd_exists(t *testing.T) {

var buf bytes.Buffer
Expand Down Expand Up @@ -82,24 +67,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 +116,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 +162,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 +179,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 +219,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 +273,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
})
}
Loading

0 comments on commit f8d96bd

Please sign in to comment.