Skip to content

Commit

Permalink
Verify that cert manager is installed (#1186)
Browse files Browse the repository at this point in the history
* Added check that cert-manager is installed if webhooks are enabled
* Refactoring for the init process

Signed-off-by: Andreas Neumann <aneumann@mesosphere.com>
  • Loading branch information
ANeumann82 committed Feb 28, 2020
1 parent 8afbb97 commit 0a0c883
Show file tree
Hide file tree
Showing 23 changed files with 581 additions and 172 deletions.
22 changes: 11 additions & 11 deletions pkg/kudoctl/cmd/init_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func TestIntegInitForCRDs(t *testing.T) {
assert.IsType(t, &meta.NoKindMatchError{}, testClient.Create(context.TODO(), instance))

// Install all of the CRDs.
crds := crd.NewInitializer().AsArray()
crds := crd.NewInitializer().Resources()
defer deleteInitObjects(testClient)

var buf bytes.Buffer
Expand Down Expand Up @@ -131,7 +131,7 @@ func TestIntegInitWithNameSpace(t *testing.T) {
assert.IsType(t, &meta.NoKindMatchError{}, testClient.Create(context.TODO(), instance))

// Install all of the CRDs.
crds := crd.NewInitializer().AsArray()
crds := crd.NewInitializer().Resources()
defer deleteInitObjects(testClient)

var buf bytes.Buffer
Expand All @@ -145,7 +145,7 @@ func TestIntegInitWithNameSpace(t *testing.T) {
// On first attempt, the namespace does not exist, so the error is expected.
err = cmd.run()
require.Error(t, err)
assert.Equal(t, err.Error(), `error installing: prerequisites: failed to install: namespace integration-test does not exist - KUDO expects that any namespace except the default kudo-system is created beforehand`)
assert.Equal(t, "error installing: Namespace integration-test does not exist - KUDO expects that any namespace except the default kudo-system is created beforehand\n", err.Error())

// Then we manually create the namespace.
ns := testutils.NewResource("v1", "Namespace", namespace, "")
Expand Down Expand Up @@ -203,7 +203,7 @@ func TestIntegInitWithServiceAccount(t *testing.T) {
assert.IsType(t, &meta.NoKindMatchError{}, testClient.Create(context.TODO(), instance))

// Install all of the CRDs.
crds := crd.NewInitializer().AsArray()
crds := crd.NewInitializer().Resources()
defer deleteInitObjects(testClient)

var buf bytes.Buffer
Expand All @@ -226,7 +226,7 @@ func TestIntegInitWithServiceAccount(t *testing.T) {
// Test Case 1, the serviceAccount does not exist, expect serviceAccount not exists error
err = cmd.run()
require.Error(t, err)
assert.Equal(t, `error installing: prerequisites: failed to install: Service Account test-account does not exists - KUDO expects the serviceAccount to be present in the namespace sa-integration-test`, err.Error())
assert.Equal(t, "error installing: Service Account test-account does not exists - KUDO expects the serviceAccount to be present in the namespace sa-integration-test\n", err.Error())

// Create the serviceAccount, in the default namespace.
ns2 := testutils.NewResource("v1", "Namespace", "test-ns", "")
Expand All @@ -241,7 +241,7 @@ func TestIntegInitWithServiceAccount(t *testing.T) {
cmd.ns = "test-ns"
err = cmd.run()
require.Error(t, err)
assert.Equal(t, `error installing: prerequisites: failed to install: Service Account sa-nonadmin does not have cluster-admin role - KUDO expects the serviceAccount passed to be in the namespace test-ns and to have cluster-admin role`, err.Error())
assert.Equal(t, "error installing: Service Account sa-nonadmin does not have cluster-admin role - KUDO expects the serviceAccount passed to be in the namespace test-ns and to have cluster-admin role\n", err.Error())

// Test case 3: Run Init command with a serviceAccount that does not have cluster-admin role.
cmd.serviceAccount = serviceAccount
Expand All @@ -252,7 +252,7 @@ func TestIntegInitWithServiceAccount(t *testing.T) {

err = cmd.run()
require.Error(t, err)
assert.Equal(t, `error installing: prerequisites: failed to install: Service Account sa-integration does not have cluster-admin role - KUDO expects the serviceAccount passed to be in the namespace sa-integration-test and to have cluster-admin role`, err.Error())
assert.Equal(t, "error installing: Service Account sa-integration does not have cluster-admin role - KUDO expects the serviceAccount passed to be in the namespace sa-integration-test and to have cluster-admin role\n", err.Error())

// Test case 4: Run Init command with a serviceAccount that does not have cluster-admin role.
crb2 := testutils.NewClusterRoleBinding("rbac.authorization.k8s.io/v1", "ClusterRoleBinding", "kudo-test2", namespace, serviceAccount, "cluster-temp")
Expand All @@ -261,7 +261,7 @@ func TestIntegInitWithServiceAccount(t *testing.T) {

err = cmd.run()
require.Error(t, err)
assert.Equal(t, `error installing: prerequisites: failed to install: Service Account sa-integration does not have cluster-admin role - KUDO expects the serviceAccount passed to be in the namespace sa-integration-test and to have cluster-admin role`, err.Error())
assert.Equal(t, "error installing: Service Account sa-integration does not have cluster-admin role - KUDO expects the serviceAccount passed to be in the namespace sa-integration-test and to have cluster-admin role\n", err.Error())

// Test case 5: Run Init command with a serviceAccount that is present in the cluster and also has cluster-admin role.
crb3 := testutils.NewClusterRoleBinding("rbac.authorization.k8s.io/v1", "ClusterRoleBinding", "kudo-clusterrole-binding", namespace, serviceAccount, "cluster-admin")
Expand Down Expand Up @@ -307,7 +307,7 @@ func TestNoErrorOnReInit(t *testing.T) {
assert.IsType(t, &meta.NoKindMatchError{}, testClient.Create(context.TODO(), instance))

// Install all of the CRDs.
crds := crd.NewInitializer().AsArray()
crds := crd.NewInitializer().Resources()
defer deleteInitObjects(testClient)

var buf bytes.Buffer
Expand Down Expand Up @@ -342,8 +342,8 @@ func TestNoErrorOnReInit(t *testing.T) {
func deleteInitObjects(client *testutils.RetryClient) {
crds := crd.NewInitializer()
prereqs := prereq.NewInitializer(kudoinit.NewOptions("", "", "", []string{}))
deleteCRDs(crds.AsArray(), client)
deletePrereq(prereqs.AsArray(), client)
deleteCRDs(crds.Resources(), client)
deletePrereq(prereqs.Resources(), client)
}

func deleteCRDs(crds []runtime.Object, client *testutils.RetryClient) {
Expand Down
4 changes: 2 additions & 2 deletions pkg/kudoctl/cmd/verify/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import (
"strings"

"github.com/kudobuilder/kudo/pkg/kudoctl/packages"
"github.com/kudobuilder/kudo/pkg/kudoctl/packages/verifier"
"github.com/kudobuilder/kudo/pkg/kudoctl/packages/verifier/plan"
"github.com/kudobuilder/kudo/pkg/kudoctl/packages/verifier/task"
"github.com/kudobuilder/kudo/pkg/kudoctl/packages/verifier/template"
"github.com/kudobuilder/kudo/pkg/kudoctl/verifier"
"github.com/kudobuilder/kudo/pkg/version"
)

var verifiers = []verifier.PackageVerifier{
var verifiers = []packages.Verifier{
DuplicateVerifier{},
InvalidCharVerifier{";,"},
K8sVersionVerifier{},
Expand Down
28 changes: 11 additions & 17 deletions pkg/kudoctl/kudoinit/crd/crds.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ import (
"github.com/kudobuilder/kudo/pkg/kudoctl/clog"
"github.com/kudobuilder/kudo/pkg/kudoctl/kube"
"github.com/kudobuilder/kudo/pkg/kudoctl/kudoinit"
"github.com/kudobuilder/kudo/pkg/kudoctl/verifier"
)

// Ensure kudoinit.InitStep is implemented
var _ kudoinit.InitStep = &Initializer{}
// Ensure kudoinit.Step is implemented
var _ kudoinit.Step = &Initializer{}

// Initializer represents custom resource definitions needed to run KUDO
type Initializer struct {
Expand All @@ -36,24 +37,17 @@ func NewInitializer() Initializer {
}
}

// AsArray returns all CRDs as array of runtime objects
func (c Initializer) AsArray() []runtime.Object {
return []runtime.Object{c.Operator, c.OperatorVersion, c.Instance}
func (c Initializer) String() string {
return "crds"
}

// AsYamlManifests returns crds as slice of strings
func (c Initializer) AsYamlManifests() ([]string, error) {
objs := c.AsArray()
manifests := make([]string, len(objs))
for i, obj := range objs {
o, err := yaml.Marshal(obj)
if err != nil {
return []string{}, err
}
manifests[i] = string(o)
}
// Resources returns all CRDs as array of runtime objects
func (c Initializer) Resources() []runtime.Object {
return []runtime.Object{c.Operator, c.OperatorVersion, c.Instance}
}

return manifests, nil
func (c Initializer) PreInstallVerify(client *kube.Client) verifier.Result {
return verifier.NewResult()
}

// Install uses Kubernetes client to install KUDO Crds.
Expand Down
37 changes: 13 additions & 24 deletions pkg/kudoctl/kudoinit/manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
appsv1client "k8s.io/client-go/kubernetes/typed/apps/v1"
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
"sigs.k8s.io/yaml"

"github.com/kudobuilder/kudo/pkg/kudoctl/clog"
"github.com/kudobuilder/kudo/pkg/kudoctl/kube"
"github.com/kudobuilder/kudo/pkg/kudoctl/kudoinit"
"github.com/kudobuilder/kudo/pkg/kudoctl/verifier"
)

// Ensure kudoinit.InitStep is implemented
var _ kudoinit.InitStep = &Initializer{}
// Ensure kudoinit.Step is implemented
var _ kudoinit.Step = &Initializer{}

//Defines the deployment of the KUDO manager and it's service definition.
type Initializer struct {
Expand All @@ -31,10 +31,6 @@ type Initializer struct {
deployment *appsv1.StatefulSet
}

func (m Initializer) AsArray() []runtime.Object {
return []runtime.Object{m.service, m.deployment}
}

// NewInitializer returns the setup management object
func NewInitializer(options kudoinit.Options) Initializer {
return Initializer{
Expand All @@ -44,6 +40,14 @@ func NewInitializer(options kudoinit.Options) Initializer {
}
}

func (m Initializer) PreInstallVerify(client *kube.Client) verifier.Result {
return verifier.NewResult()
}

func (m Initializer) String() string {
return "kudo controller"
}

// Install uses Kubernetes client to install KUDO.
func (m Initializer) Install(client *kube.Client) error {
if err := m.installStatefulSet(client.KubeClient.AppsV1()); err != nil {
Expand Down Expand Up @@ -80,23 +84,8 @@ func (m Initializer) installService(client corev1.ServicesGetter) error {
return err
}

// AsYamlManifests provides a slice of strings for the deployment and service manifest
func (m Initializer) AsYamlManifests() ([]string, error) {
s := m.service
d := m.deployment

objs := []runtime.Object{s, d}

manifests := make([]string, len(objs))
for i, obj := range objs {
o, err := yaml.Marshal(obj)
if err != nil {
return []string{}, err
}
manifests[i] = string(o)
}

return manifests, nil
func (m Initializer) Resources() []runtime.Object {
return []runtime.Object{m.service, m.deployment}
}

// GenerateLabels returns the labels used by deployment and service
Expand Down
24 changes: 12 additions & 12 deletions pkg/kudoctl/kudoinit/prereq/namespace.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/kudobuilder/kudo/pkg/kudoctl/clog"
"github.com/kudobuilder/kudo/pkg/kudoctl/kube"
"github.com/kudobuilder/kudo/pkg/kudoctl/kudoinit"
"github.com/kudobuilder/kudo/pkg/kudoctl/verifier"
)

// Ensure IF is implemented
Expand All @@ -21,6 +22,17 @@ type kudoNamespace struct {
ns *v1.Namespace
}

func (o kudoNamespace) PreInstallVerify(client *kube.Client) verifier.Result {
// We only manage kudo-system namespace. For others we expect they exist.
if !o.opts.IsDefaultNamespace() {
_, err := client.KubeClient.CoreV1().Namespaces().Get(o.opts.Namespace, metav1.GetOptions{})
if kerrors.IsNotFound(err) {
return verifier.NewError(fmt.Sprintf("Namespace %s does not exist - KUDO expects that any namespace except the default %s is created beforehand", o.opts.Namespace, kudoinit.DefaultNamespace))
}
}
return verifier.NewResult()
}

func newNamespace(options kudoinit.Options) kudoNamespace {
return kudoNamespace{
opts: options,
Expand All @@ -29,18 +41,6 @@ func newNamespace(options kudoinit.Options) kudoNamespace {
}

func (o kudoNamespace) Install(client *kube.Client) error {
// We only manage kudo-system namespace. For others we expect they exist.
if !o.opts.IsDefaultNamespace() {
_, err := client.KubeClient.CoreV1().Namespaces().Get(o.opts.Namespace, metav1.GetOptions{})
if err == nil {
return nil
}
if kerrors.IsNotFound(err) {
return fmt.Errorf("namespace %s does not exist - KUDO expects that any namespace except the default %s is created beforehand", o.opts.Namespace, kudoinit.DefaultNamespace)
}
return err
}

_, err := client.KubeClient.CoreV1().Namespaces().Create(o.ns)
if kerrors.IsAlreadyExists(err) {
clog.V(4).Printf("namespace %v already exists", o.ns.Name)
Expand Down
32 changes: 32 additions & 0 deletions pkg/kudoctl/kudoinit/prereq/namespace_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package prereq

import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/kudobuilder/kudo/pkg/kudoctl/kudoinit"
"github.com/kudobuilder/kudo/pkg/kudoctl/verifier"
)

func TestPrereq_Fail_PreValidate_CustomNamespace(t *testing.T) {
client := getFakeClient()

init := NewInitializer(kudoinit.NewOptions("", "customNS", "", make([]string, 0)))

result := init.PreInstallVerify(client)

assert.EqualValues(t, verifier.NewError("Namespace customNS does not exist - KUDO expects that any namespace except the default kudo-system is created beforehand"), result)
}

func TestPrereq_Ok_PreValidate_CustomNamespace(t *testing.T) {
client := getFakeClient()

mockGetNamespace(client, "customNS")

init := NewInitializer(kudoinit.NewOptions("", "customNS", "", make([]string, 0)))

result := init.PreInstallVerify(client)

assert.EqualValues(t, verifier.NewResult(), result)
}
39 changes: 20 additions & 19 deletions pkg/kudoctl/kudoinit/prereq/prereqs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@ import (
"fmt"

"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/yaml"

"github.com/kudobuilder/kudo/pkg/kudoctl/kube"
"github.com/kudobuilder/kudo/pkg/kudoctl/kudoinit"
"github.com/kudobuilder/kudo/pkg/kudoctl/verifier"
)

// Ensure kudoinit.InitStep is implemented
var _ kudoinit.InitStep = &Initializer{}
// Ensure kudoinit.Step is implemented
var _ kudoinit.Step = &Initializer{}

// Defines a single prerequisite that is defined as a k8s resource
type k8sResource interface {
// PreInstallVerify is called before the installation of any component is started and should return an error if the installation is not possible
PreInstallVerify(client *kube.Client) verifier.Result

// Install installs the manifests of this prerequisite
Install(client *kube.Client) error

Expand Down Expand Up @@ -42,6 +45,19 @@ func NewInitializer(options kudoinit.Options) Initializer {
}
}

func (p Initializer) String() string {
return "service accounts and other requirements for controller to run"
}

func (p Initializer) PreInstallVerify(client *kube.Client) verifier.Result {
result := verifier.NewResult()
for _, prereq := range p.prereqs {
res := prereq.PreInstallVerify(client)
result.Merge(res)
}
return result
}

func (p Initializer) Install(client *kube.Client) error {
for _, prereq := range p.prereqs {
err := prereq.Install(client)
Expand All @@ -52,26 +68,11 @@ func (p Initializer) Install(client *kube.Client) error {
return nil
}

func (p Initializer) AsArray() []runtime.Object {
func (p Initializer) Resources() []runtime.Object {
var prereqs []runtime.Object

for _, prereq := range p.prereqs {
prereqs = append(prereqs, prereq.AsRuntimeObjs()...)
}
return prereqs
}

func (p Initializer) AsYamlManifests() ([]string, error) {
prereqs := p.AsArray()

manifests := make([]string, len(prereqs))
for i, obj := range prereqs {
o, err := yaml.Marshal(obj)
if err != nil {
return []string{}, err
}
manifests[i] = string(o)
}

return manifests, nil
}
Loading

0 comments on commit 0a0c883

Please sign in to comment.