Skip to content

Commit cae79f9

Browse files
committed
fix: use OLM client when installing CRDs
1 parent 4a9d02b commit cae79f9

File tree

2 files changed

+271
-1
lines changed

2 files changed

+271
-1
lines changed

pkg/controller/operators/catalog/operator.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1578,7 +1578,16 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
15781578

15791579
ensurer := newStepEnsurer(kubeclient, crclient, dynamicClient)
15801580
r := newManifestResolver(plan.GetNamespace(), o.lister.CoreV1().ConfigMapLister(), o.logger)
1581-
b := newBuilder(kubeclient, dynamicClient, o.csvProvidedAPIsIndexer, r, o.logger)
1581+
1582+
// CRDs should be installed via the default OLM (cluster-admin) client and not the scoped client specified by the AttenuatedServiceAccount
1583+
// the StepBuilder is currently only implemented for CRD types
1584+
// TODO give the StepBuilder both OLM and scoped clients when it supports new scoped types
1585+
builderKubeClient, _, builderDynamicClient, err := o.clientAttenuator.AttenuateClientWithServiceAccount(nil)
1586+
if err != nil {
1587+
o.logger.Errorf("failed to get a client for plan execution- %v", err)
1588+
return err
1589+
}
1590+
b := newBuilder(builderKubeClient, builderDynamicClient, o.csvProvidedAPIsIndexer, r, o.logger)
15821591

15831592
for i, step := range plan.Status.Plan {
15841593
doStep := true

test/e2e/installplan_e2e_test.go

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2803,6 +2803,267 @@ var _ = Describe("Install Plan", func() {
28032803
Expect(ref.Kind).To(Equal("ConfigMap"))
28042804
}
28052805
})
2806+
It("uses the OLM client when installing CRDs from a bundle", func() {
2807+
c := newKubeClient()
2808+
crc := newCRClient()
2809+
2810+
By("creating a scoped serviceaccount specifified in the operatorgroup")
2811+
ns, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
2812+
ObjectMeta: metav1.ObjectMeta{
2813+
Name: genName("ns-"),
2814+
},
2815+
}, metav1.CreateOptions{})
2816+
Expect(err).ToNot(HaveOccurred())
2817+
defer c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), ns.GetName(), metav1.DeleteOptions{})
2818+
2819+
// create SA
2820+
sa := &corev1.ServiceAccount{
2821+
ObjectMeta: metav1.ObjectMeta{
2822+
Name: genName("sa-"),
2823+
Namespace: ns.GetName(),
2824+
},
2825+
}
2826+
_, err = c.KubernetesInterface().CoreV1().ServiceAccounts(ns.GetName()).Create(context.TODO(), sa, metav1.CreateOptions{})
2827+
Expect(err).ToNot(HaveOccurred())
2828+
2829+
// create role that includes permission for installing the kiali operator, but not CRDs
2830+
// see https://github.com/operator-framework/operator-lifecycle-manager/blob/master/doc/design/scoped-operator-install.md
2831+
role := &rbacv1.ClusterRole{
2832+
ObjectMeta: metav1.ObjectMeta{
2833+
Name: genName("role-"),
2834+
},
2835+
Rules: []rbacv1.PolicyRule{
2836+
{
2837+
APIGroups: []string{"operators.coreos.com"},
2838+
Resources: []string{"subscriptions", "clusterserviceversions"},
2839+
Verbs: []string{"get", "create", "update", "patch"},
2840+
},
2841+
{
2842+
APIGroups: []string{""},
2843+
Resources: []string{"services", "serviceaccounts", "configmaps", "endpoints", "events", "persistentvolumeclaims", "pods"},
2844+
Verbs: []string{"create", "delete", "get", "list", "update", "patch", "watch"},
2845+
},
2846+
{
2847+
APIGroups: []string{""},
2848+
Resources: []string{"namespaces", "nodes", "pods/log", "replicationcontrollers"},
2849+
Verbs: []string{"list", "get", "patch", "watch"},
2850+
},
2851+
{
2852+
APIGroups: []string{"apps"},
2853+
Resources: []string{"deployments", "replicasets", "statefulsets"},
2854+
Verbs: []string{"list", "watch", "get", "create", "update", "patch", "delete"},
2855+
},
2856+
{
2857+
APIGroups: []string{"monitoring.coreos.com"},
2858+
Resources: []string{"servicemonitors"},
2859+
Verbs: []string{"create", "get"},
2860+
},
2861+
{
2862+
APIGroups: []string{"apps"},
2863+
Resources: []string{"deployments/finalizers"},
2864+
ResourceNames: []string{"kiali-operator"},
2865+
Verbs: []string{"update"},
2866+
},
2867+
{
2868+
APIGroups: []string{"kiali.io"},
2869+
Resources: []string{"*"},
2870+
Verbs: []string{"*"},
2871+
},
2872+
{
2873+
APIGroups: []string{"rbac.authorization.k8s.io"},
2874+
Resources: []string{"*"},
2875+
Verbs: []string{"*"},
2876+
},
2877+
{
2878+
// ability to get and list CRDs, but not create CRDs
2879+
APIGroups: []string{"apiextensions.k8s.io"},
2880+
Resources: []string{"customresourcedefinitions"},
2881+
Verbs: []string{"get", "list", "watch"},
2882+
},
2883+
{
2884+
APIGroups: []string{"extensions"},
2885+
Resources: []string{"*"},
2886+
Verbs: []string{"*"},
2887+
},
2888+
{
2889+
APIGroups: []string{"route.openshift.io"},
2890+
Resources: []string{"routes"},
2891+
Verbs: []string{"*"},
2892+
},
2893+
{
2894+
APIGroups: []string{"oauth.openshift.io"},
2895+
Resources: []string{"oauthclients"},
2896+
Verbs: []string{"*"},
2897+
},
2898+
{
2899+
APIGroups: []string{"monitoring.kiali.io"},
2900+
Resources: []string{"monitoringdashboards"},
2901+
Verbs: []string{"*"},
2902+
},
2903+
{
2904+
APIGroups: []string{"autoscaling"},
2905+
Resources: []string{"horizontalpodautoscalers"},
2906+
Verbs: []string{"get", "list", "watch"},
2907+
},
2908+
{
2909+
APIGroups: []string{"batch"},
2910+
Resources: []string{"*"},
2911+
Verbs: []string{"*"},
2912+
},
2913+
{
2914+
APIGroups: []string{"config.istio.io"},
2915+
Resources: []string{"*"},
2916+
Verbs: []string{"*"},
2917+
},
2918+
{
2919+
APIGroups: []string{"networking.istio.io"},
2920+
Resources: []string{"*"},
2921+
Verbs: []string{"*"},
2922+
},
2923+
{
2924+
APIGroups: []string{"authentication.istio.io"},
2925+
Resources: []string{"*"},
2926+
Verbs: []string{"*"},
2927+
},
2928+
{
2929+
APIGroups: []string{"rbac.istio.io"},
2930+
Resources: []string{"*"},
2931+
Verbs: []string{"*"},
2932+
},
2933+
{
2934+
APIGroups: []string{"authentication.maistra.io"},
2935+
Resources: []string{"servicemeshpolicies"},
2936+
Verbs: []string{"*"},
2937+
},
2938+
{
2939+
APIGroups: []string{"rbac.maistra.io"},
2940+
Resources: []string{"servicemeshrbacconfigs"},
2941+
Verbs: []string{"*"},
2942+
},
2943+
{
2944+
APIGroups: []string{"apps.openshift.io"},
2945+
Resources: []string{"deploymentconfigs"},
2946+
Verbs: []string{"*"},
2947+
},
2948+
{
2949+
APIGroups: []string{"project.openshift.io"},
2950+
Resources: []string{"projects"},
2951+
Verbs: []string{"get"},
2952+
},
2953+
{
2954+
APIGroups: []string{"route.openshift.io"},
2955+
Resources: []string{"routes"},
2956+
Verbs: []string{"get"},
2957+
},
2958+
{
2959+
APIGroups: []string{"monitoring.kiali.io"},
2960+
Resources: []string{"monitoringdashboards"},
2961+
Verbs: []string{"get", "list"},
2962+
},
2963+
},
2964+
}
2965+
2966+
_, err = c.KubernetesInterface().RbacV1().ClusterRoles().Create(context.TODO(), role, metav1.CreateOptions{})
2967+
Expect(err).ToNot(HaveOccurred())
2968+
2969+
// bind role to SA
2970+
rb := &rbacv1.ClusterRoleBinding{
2971+
ObjectMeta: metav1.ObjectMeta{
2972+
Name: genName("rb-"),
2973+
},
2974+
RoleRef: rbacv1.RoleRef{
2975+
Name: role.GetName(),
2976+
Kind: "ClusterRole",
2977+
APIGroup: "rbac.authorization.k8s.io",
2978+
},
2979+
Subjects: []rbacv1.Subject{
2980+
{
2981+
Kind: "ServiceAccount",
2982+
Name: sa.GetName(),
2983+
APIGroup: "",
2984+
Namespace: sa.GetNamespace(),
2985+
},
2986+
},
2987+
}
2988+
2989+
_, err = c.KubernetesInterface().RbacV1().ClusterRoleBindings().Create(context.TODO(), rb, metav1.CreateOptions{})
2990+
Expect(err).ToNot(HaveOccurred())
2991+
defer c.KubernetesInterface().RbacV1().ClusterRoles().Delete(context.TODO(), role.GetName(), metav1.DeleteOptions{})
2992+
2993+
// create operator group referencing the SA
2994+
og := &operatorsv1.OperatorGroup{
2995+
ObjectMeta: metav1.ObjectMeta{
2996+
Name: genName("og-"),
2997+
Namespace: ns.GetName(),
2998+
},
2999+
Spec: operatorsv1.OperatorGroupSpec{
3000+
ServiceAccountName: sa.GetName(),
3001+
},
3002+
}
3003+
_, err = crc.OperatorsV1().OperatorGroups(ns.GetName()).Create(context.TODO(), og, metav1.CreateOptions{})
3004+
Expect(err).ToNot(HaveOccurred())
3005+
3006+
By("using the OLM client to install CRDs from the bundle and the scoped client for other resources")
3007+
// create catalog and subscription
3008+
catsrc := &operatorsv1alpha1.CatalogSource{
3009+
ObjectMeta: metav1.ObjectMeta{
3010+
Name: genName("kiali-"),
3011+
Namespace: ns.GetName(),
3012+
Labels: map[string]string{"olm.catalogSource": "kaili-catalog"},
3013+
},
3014+
Spec: operatorsv1alpha1.CatalogSourceSpec{
3015+
Image: "quay.io/olmtest/single-bundle-index:1.0.0",
3016+
SourceType: operatorsv1alpha1.SourceTypeGrpc,
3017+
},
3018+
}
3019+
catsrc, err = crc.OperatorsV1alpha1().CatalogSources(catsrc.GetNamespace()).Create(context.TODO(), catsrc, metav1.CreateOptions{})
3020+
Expect(err).ToNot(HaveOccurred())
3021+
defer crc.OperatorsV1alpha1().CatalogSources(catsrc.GetNamespace()).Delete(context.TODO(), catsrc.GetName(), metav1.DeleteOptions{})
3022+
3023+
// Wait for the CatalogSource to be ready
3024+
catsrc, err = fetchCatalogSourceOnStatus(crc, catsrc.GetName(), catsrc.GetNamespace(), catalogSourceRegistryPodSynced)
3025+
Expect(err).ToNot(HaveOccurred())
3026+
3027+
// Generate a Subscription
3028+
subName := genName("kiali-")
3029+
subCleanup := createSubscriptionForCatalog(crc, catsrc.GetNamespace(), subName, catsrc.GetName(), "kiali", stableChannel, "", operatorsv1alpha1.ApprovalAutomatic)
3030+
defer subCleanup()
3031+
3032+
sub, err := fetchSubscription(crc, catsrc.GetNamespace(), subName, subscriptionHasInstallPlanChecker)
3033+
Expect(err).ToNot(HaveOccurred())
3034+
3035+
// Wait for the expected InstallPlan's execution to succeed
3036+
ipName := sub.Status.InstallPlanRef.Name
3037+
ip, err := waitForInstallPlan(crc, ipName, sub.GetNamespace(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseFailed, operatorsv1alpha1.InstallPlanPhaseComplete))
3038+
Expect(err).ToNot(HaveOccurred())
3039+
Expect(operatorsv1alpha1.InstallPlanPhaseComplete).To(Equal(ip.Status.Phase), "InstallPlan not complete")
3040+
3041+
// ensure expected kiali CRDs are present on-cluster
3042+
expectedCRDs := []metav1.GroupVersionKind{
3043+
{
3044+
Group: "kialis.kiali.io",
3045+
Version: "v1alpha1",
3046+
Kind: "CustomResourceDefinition",
3047+
},
3048+
{
3049+
Group: "monitoringdashboards.monitoring.kiali.io",
3050+
Version: "v1alpha1",
3051+
Kind: "CustomResourceDefinition",
3052+
},
3053+
}
3054+
3055+
for _, crd := range expectedCRDs {
3056+
Eventually(func() error {
3057+
defer Eventually(func() bool {
3058+
err = c.ApiextensionsInterface().ApiextensionsV1beta1().CustomResourceDefinitions().Delete(context.TODO(), crd.Group, metav1.DeleteOptions{GracePeriodSeconds: new(int64)})
3059+
return k8serrors.IsNotFound(err)
3060+
}).Should(BeTrue())
3061+
3062+
_, err = c.ApiextensionsInterface().ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), crd.Group, metav1.GetOptions{})
3063+
return err
3064+
}).ShouldNot(HaveOccurred())
3065+
}
3066+
})
28063067
})
28073068

28083069
type checkInstallPlanFunc func(fip *operatorsv1alpha1.InstallPlan) bool

0 commit comments

Comments
 (0)