Skip to content

Commit

Permalink
Merge pull request operator-framework#1391 from benluddy/helm3-chart
Browse files Browse the repository at this point in the history
Update chart to use the new "crds" directory.
  • Loading branch information
openshift-merge-robot authored and awgreene committed Mar 20, 2020
2 parents a6162e4 + 1bf7d62 commit 64f3b12
Show file tree
Hide file tree
Showing 351 changed files with 23,985 additions and 5,424 deletions.
4 changes: 2 additions & 2 deletions Makefile
Expand Up @@ -156,9 +156,9 @@ clean:

# Generate manifests for CRDs
manifests: vendor
$(CONTROLLER_GEN) schemapatch:manifests=./deploy/chart/templates paths=./pkg/api/apis/operators/... output:dir=./deploy/chart/templates
$(CONTROLLER_GEN) schemapatch:manifests=./deploy/chart/crds paths=./pkg/api/apis/operators/... output:dir=./deploy/chart/crds

$(YQ_INTERNAL) w --inplace deploy/chart/templates/0000_50_olm_03-clusterserviceversion.crd.yaml spec.validation.openAPIV3Schema.properties.spec.properties.install.properties.spec.properties.deployments.items.properties.spec.properties.template.properties.metadata.x-kubernetes-preserve-unknown-fields true
$(YQ_INTERNAL) w --inplace deploy/chart/crds/0000_50_olm_03-clusterserviceversion.crd.yaml spec.validation.openAPIV3Schema.properties.spec.properties.install.properties.spec.properties.deployments.items.properties.spec.properties.template.properties.metadata.x-kubernetes-preserve-unknown-fields true

# Generate clients, listers, and informers
codegen:
Expand Down
2 changes: 1 addition & 1 deletion deploy/chart/Chart.yaml
@@ -1,3 +1,3 @@
apiVersion: v1
apiVersion: v2
description: A Helm chart for Kubernetes
name: olm
16 changes: 9 additions & 7 deletions go.mod
Expand Up @@ -8,6 +8,7 @@ require (
github.com/fsnotify/fsnotify v1.4.7
github.com/ghodss/yaml v1.0.0
github.com/go-openapi/spec v0.19.4
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/mock v1.3.1
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2
github.com/mikefarah/yq/v2 v2.4.1
Expand All @@ -18,19 +19,19 @@ require (
github.com/openshift/client-go v0.0.0-20190923180330-3b6373338c9b
github.com/operator-framework/operator-registry v1.5.8
github.com/otiai10/copy v1.0.1
github.com/pkg/errors v0.8.1
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.2.1
github.com/sirupsen/logrus v1.4.2
github.com/spf13/cobra v0.0.5
github.com/stretchr/testify v1.4.0
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
google.golang.org/grpc v1.24.0
google.golang.org/grpc v1.27.0
gopkg.in/yaml.v2 v2.2.4
helm.sh/helm/v3 v3.0.1
k8s.io/api v0.17.1
k8s.io/apiextensions-apiserver v0.17.1
k8s.io/apimachinery v0.17.1
helm.sh/helm/v3 v3.1.2
k8s.io/api v0.17.2
k8s.io/apiextensions-apiserver v0.17.2
k8s.io/apimachinery v0.17.2
k8s.io/apiserver v0.0.0
k8s.io/client-go v8.0.0+incompatible
k8s.io/code-generator v0.0.0
Expand All @@ -43,11 +44,12 @@ require (
)

replace (
github.com/Azure/go-autorest => github.com/Azure/go-autorest v13.3.2+incompatible
github.com/docker/docker => github.com/moby/moby v0.7.3-0.20190826074503-38ab9da00309 // Required by Helm
github.com/openshift/api => github.com/openshift/api v3.9.1-0.20190924102528-32369d4db2ad+incompatible
github.com/openshift/client-go => github.com/openshift/client-go v0.0.0-20190923180330-3b6373338c9b
github.com/prometheus/client_golang => github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829
helm.sh/helm/v3 => helm.sh/helm/v3 v3.0.0-beta.5.0.20200123114618-5e3c7d7eb86a
google.golang.org/grpc => google.golang.org/grpc v1.26.0 // https://github.com/etcd-io/etcd/issues/11563

// Pin to kube 1.16
k8s.io/api => k8s.io/api v0.0.0-20190918155943-95b840bb6a1f
Expand Down
147 changes: 126 additions & 21 deletions go.sum

Large diffs are not rendered by default.

110 changes: 110 additions & 0 deletions pkg/controller/operators/olm/operatorgroup.go
Expand Up @@ -27,6 +27,8 @@ const (
AdminSuffix = "admin"
EditSuffix = "edit"
ViewSuffix = "view"

operatorGroupLabelTemplate = "olm.operatorgroup/%s.%s"
)

var (
Expand Down Expand Up @@ -98,6 +100,10 @@ func (a *Operator) syncOperatorGroups(obj interface{}) error {
logger.WithField("targetNamespaces", targetNamespaces).Debug("updated target namespaces")

if namespacesChanged(targetNamespaces, op.Status.Namespaces) {
// Labels are only applied to namespaces that are not empty strings.
prunedStatusNamespaces := pruneEmptyStrings(op.Status.Namespaces)
prunedTargetNamespaces := pruneEmptyStrings(targetNamespaces)

// Update operatorgroup target namespace selection
logger.WithField("targets", targetNamespaces).Debug("namespace change detected")
op.Status = v1.OperatorGroupStatus{
Expand All @@ -109,6 +115,26 @@ func (a *Operator) syncOperatorGroups(obj interface{}) error {
logger.WithError(err).Warn("operatorgroup update failed")
return err
}

// Update which namepspaces have the OperatorGroup label.
ogLabel := getOperatorGroupLabel(*op)
// Remove labels from targetNamespaces that were dropped.
for _, namespaceName := range setDifference(prunedStatusNamespaces, prunedTargetNamespaces) {
err = a.removeNamespaceLabel(namespaceName, ogLabel)
if err != nil {
logger.WithError(err).Warnf("failed to remove operatorgroup label from namespace %s", namespaceName)
return err
}
}

// Add labels to targetNamespaces that were added.
for _, namespaceName := range setDifference(prunedTargetNamespaces, prunedStatusNamespaces) {
err = a.addNamespaceLabel(namespaceName, ogLabel, "")
if err != nil {
logger.WithError(err).Warnf("failed to add operatorgroup to from namespace %s", namespaceName)
return err
}
}
logger.Debug("namespace change detected and operatorgroup status updated")
// CSV requeue is handled by the succeeding sync in `annotateCSVs`
return nil
Expand Down Expand Up @@ -160,6 +186,43 @@ func (a *Operator) syncOperatorGroups(obj interface{}) error {
return nil
}

// pruneEmptyStrings removes any items from a list that are empty
func pruneEmptyStrings(namespaceNames []string) []string {
prunedString := []string{}
for _, namespaceName := range namespaceNames {
if namespaceName != "" {
prunedString = append(prunedString, namespaceName)
}
}
return prunedString
}

// setDifference implements Set Difference: A - B
// https://en.wikipedia.org/wiki/Complement_(set_theory)#In_programming_languages
func setDifference(a, b []string) (diff []string) {
if len(a) == 0 {
return diff
}

if len(b) == 0 {
return a
}

// Find the Set Difference.
m := make(map[string]bool)

for _, item := range b {
m[item] = true
}

for _, item := range a {
if _, ok := m[item]; !ok {
diff = append(diff, item)
}
}
return diff
}

func (a *Operator) operatorGroupDeleted(obj interface{}) {
op, ok := obj.(*v1.OperatorGroup)
if !ok {
Expand All @@ -183,6 +246,53 @@ func (a *Operator) operatorGroupDeleted(obj interface{}) {
logger.WithError(err).Error("failed to delete ClusterRole during garbage collection")
}
}

// Remove OperatorGroup label from targeNamespaces.
ogLabel := getOperatorGroupLabel(*op)
for _, namespaceName := range op.Spec.TargetNamespaces {
a.removeNamespaceLabel(namespaceName, ogLabel)
if err != nil {
logger.WithError(err).Error("failed to remove OperatorGroup Label from Namespace during garbage collection")
}
}
}

func (a *Operator) updateNamespace(namespaceName string, namespaceUpdateFunc func(*corev1.Namespace)) error {
namespace, err := a.opClient.KubernetesInterface().CoreV1().Namespaces().Get(namespaceName, metav1.GetOptions{})
if err != nil {
return err
}

namespaceUpdateFunc(namespace)

_, err = a.opClient.KubernetesInterface().CoreV1().Namespaces().Update(namespace)
if err != nil {
return err
}
return nil
}

func (a *Operator) removeNamespaceLabel(namespaceName, key string) error {
namespaceUpdateFunc := func(namespace *corev1.Namespace) {
delete(namespace.Labels, key)
}
return a.updateNamespace(namespaceName, namespaceUpdateFunc)
}

func (a *Operator) addNamespaceLabel(namespaceName string, key, value string) error {
namespaceUpdateFunc := func(namespace *corev1.Namespace) {
if namespace.Labels == nil {
namespace.Labels = make(map[string]string, 1)
}
namespace.Labels[key] = value
}
return a.updateNamespace(namespaceName, namespaceUpdateFunc)
}

// getOperatorGroupLabel returns a label that is applied to Namespaces to signify that the
// namespace is a part of the operator group using selectors.
func getOperatorGroupLabel(og v1.OperatorGroup) string {
return fmt.Sprintf(operatorGroupLabelTemplate, og.GetNamespace(), og.GetName())
}

func (a *Operator) annotateCSVs(group *v1.OperatorGroup, targetNamespaces []string, logger *logrus.Entry) error {
Expand Down
4 changes: 2 additions & 2 deletions scripts/package_release.sh
Expand Up @@ -21,6 +21,6 @@ echo "Version: $1" >> ${charttmpdir}/Chart.yaml

mkdir -p ${chartdir}

go run -mod=vendor helm.sh/helm/v3/cmd/helm template -n olm -f ${values} ${charttmpdir} --output-dir ${charttmpdir}
go run -mod=vendor helm.sh/helm/v3/cmd/helm template -n olm -f ${values} --include-crds --output-dir ${charttmpdir} ${charttmpdir}

cp -R ${charttmpdir}/olm/templates/. ${chartdir}
cp -R "${charttmpdir}"/olm/{templates,crds}/. "${chartdir}"
143 changes: 143 additions & 0 deletions test/e2e/operator_groups_e2e_test.go
Expand Up @@ -14,6 +14,7 @@ import (
"k8s.io/apimachinery/pkg/api/errors"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
Expand All @@ -22,6 +23,7 @@ import (
. "github.com/onsi/ginkgo"
v1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1"
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry"
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
Expand Down Expand Up @@ -2115,3 +2117,144 @@ func createProjectAdmin(t GinkgoTInterface, c operatorclient.ClientInterface, na
_ = c.DeleteRoleBinding(rb.GetNamespace(), rb.GetName(), metav1.NewDeleteOptions(0))
}
}

func TestOperatorGroupLabels(t *testing.T) {
defer cleaner.NotifyTestComplete(t, true)

c := newKubeClient(t)
crc := newCRClient(t)

// Create the namespaces that will have an OperatorGroup Label applied.
testNamespaceA := genName("namespace-a-")
testNamespaceB := genName("namespace-b-")
testNamespaceC := genName("namespace-c-")
testNamespaces := []string{
testNamespaceA, testNamespaceB, testNamespaceC,
}

// Create the namespaces
for _, namespace := range testNamespaces {
_, err := c.KubernetesInterface().CoreV1().Namespaces().Create(&corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
},
})
require.NoError(t, err)
}

// Cleanup namespaces
defer func() {
for _, namespace := range testNamespaces {
err := c.KubernetesInterface().CoreV1().Namespaces().Delete(namespace, &metav1.DeleteOptions{})
require.NoError(t, err)
}
}()

// Create an OperatorGroup
operatorGroupName := genName("e2e-operator-group-")
operatorGroup := &v1.OperatorGroup{
ObjectMeta: metav1.ObjectMeta{
Name: operatorGroupName,
Namespace: testNamespaceA,
},
Spec: v1.OperatorGroupSpec{
TargetNamespaces: []string{testNamespaceA},
},
}
_, err := crc.OperatorsV1().OperatorGroups(testNamespaceA).Create(operatorGroup)
require.NoError(t, err)

// Cleanup OperatorGroup
defer func() {
err := crc.OperatorsV1().OperatorGroups(testNamespaceA).Delete(operatorGroupName, &metav1.DeleteOptions{})
require.NoError(t, err)
}()

// Create the OperatorGroup Label
ogLabel := fmt.Sprintf("olm.operatorgroup/%s.%s", testNamespaceA, operatorGroupName)

// Create list options
listOptions := metav1.ListOptions{
LabelSelector: labels.Set(map[string]string{ogLabel: ""}).String(),
}

namespaceList, err := pollForListCount(c, listOptions, 1)
require.NoError(t, err)

// Update the OperatorGroup to be global
operatorGroup.Spec.TargetNamespaces = []string{}
updateOGSpecFunc := updateOperatorGroupSpecFunc(t, crc, testNamespaceA, operatorGroupName)
require.NoError(t, retry.RetryOnConflict(retry.DefaultBackoff, updateOGSpecFunc(operatorGroup.Spec)))

namespaceList, err = pollForListCount(c, listOptions, 0)
require.NoError(t, err)

// Add namespace-a and namespace-c to the the OperatorGroup
operatorGroup.Spec.TargetNamespaces = []string{testNamespaceA, testNamespaceC}
require.NoError(t, retry.RetryOnConflict(retry.DefaultBackoff, updateOGSpecFunc(operatorGroup.Spec)))

namespaceList, err = pollForListCount(c, listOptions, 2)
require.NoError(t, err)

require.True(t, checkForOperatorGroupLabels(operatorGroup, namespaceList.Items))

// Add namespace-a, namespace-b, and namespace-c to the the OperatorGroup
operatorGroup.Spec.TargetNamespaces = []string{testNamespaceA, testNamespaceB, testNamespaceC}
require.NoError(t, retry.RetryOnConflict(retry.DefaultBackoff, updateOGSpecFunc(operatorGroup.Spec)))

namespaceList, err = pollForListCount(c, listOptions, 3)
require.NoError(t, err)

require.True(t, checkForOperatorGroupLabels(operatorGroup, namespaceList.Items))

// Update the OperatorGroup to be global
operatorGroup.Spec.TargetNamespaces = []string{}
require.NoError(t, retry.RetryOnConflict(retry.DefaultBackoff, updateOGSpecFunc(operatorGroup.Spec)))

namespaceList, err = pollForListCount(c, listOptions, 0)
require.NoError(t, err)
}

func checkForOperatorGroupLabels(operatorGroup *v1.OperatorGroup, namespaces []corev1.Namespace) bool {
for _, ns := range operatorGroup.Spec.TargetNamespaces {
if !containsNamespace(namespaces, ns) {
return false
}
}
return true
}

func updateOperatorGroupSpecFunc(t *testing.T, crc versioned.Interface, namespace, operatorGroupName string) func(v1.OperatorGroupSpec) func() error {
return func(operatorGroupSpec v1.OperatorGroupSpec) func() error {
return func() error {
fetchedOG, err := crc.OperatorsV1().OperatorGroups(namespace).Get(operatorGroupName, metav1.GetOptions{})
require.NoError(t, err)
fetchedOG.Spec = operatorGroupSpec
_, err = crc.OperatorsV1().OperatorGroups(namespace).Update(fetchedOG)
return err
}
}
}

func pollForListCount(c operatorclient.ClientInterface, listOptions metav1.ListOptions, expectedLength int) (list *corev1.NamespaceList, err error) {
wait.PollImmediate(pollInterval, pollDuration, func() (bool, error) {
list, err = c.KubernetesInterface().CoreV1().Namespaces().List(listOptions)
if err != nil {
return false, err
}
if len(list.Items) == expectedLength {
return true, nil
}
return false, nil
})
return
}

func containsNamespace(namespaces []corev1.Namespace, namespaceName string) bool {
for i := range namespaces {
if namespaces[i].GetName() == namespaceName {
return true
}
}
return false
}
4 changes: 3 additions & 1 deletion vendor/github.com/Masterminds/vcs/.travis.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 64f3b12

Please sign in to comment.