Skip to content

Commit 95b9f0d

Browse files
authored
✨ Wire up Service Account (#1038)
* add logic to return service account Signed-off-by: Ish Shah <[email protected]> * update permissions and anon token Signed-off-by: Ish Shah <[email protected]> * updated role yaml Signed-off-by: Ish Shah <[email protected]> * clean up imports Signed-off-by: Ish Shah <[email protected]> * update e2e tests Signed-off-by: Ish Shah <[email protected]> * fix lint Signed-off-by: Ish Shah <[email protected]> * extension developer test fixed Signed-off-by: Ish Shah <[email protected]> * stand up sa for upgrade test Signed-off-by: Ish Shah <[email protected]> * fixed upgrade test Signed-off-by: Ish Shah <[email protected]> * linting for extension test Signed-off-by: Ish Shah <[email protected]> --------- Signed-off-by: Ish Shah <[email protected]>
1 parent 775613f commit 95b9f0d

File tree

7 files changed

+238
-28
lines changed

7 files changed

+238
-28
lines changed

cmd/manager/main.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,17 @@ import (
2222
"fmt"
2323
"os"
2424
"path/filepath"
25+
"time"
2526

2627
"github.com/spf13/pflag"
2728
"go.uber.org/zap/zapcore"
2829
apiextensionsv1client "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1"
2930
k8slabels "k8s.io/apimachinery/pkg/labels"
3031
"k8s.io/apimachinery/pkg/selection"
32+
"k8s.io/apimachinery/pkg/types"
33+
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
3134
_ "k8s.io/client-go/plugin/pkg/client/auth"
35+
"k8s.io/client-go/rest"
3236
ctrl "sigs.k8s.io/controller-runtime"
3337
crcache "sigs.k8s.io/controller-runtime/pkg/cache"
3438
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -42,6 +46,7 @@ import (
4246

4347
ocv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1"
4448
"github.com/operator-framework/operator-controller/internal/action"
49+
"github.com/operator-framework/operator-controller/internal/authentication"
4550
"github.com/operator-framework/operator-controller/internal/catalogmetadata/cache"
4651
catalogclient "github.com/operator-framework/operator-controller/internal/catalogmetadata/client"
4752
"github.com/operator-framework/operator-controller/internal/controllers"
@@ -158,9 +163,34 @@ func main() {
158163
ext := obj.(*ocv1alpha1.ClusterExtension)
159164
return ext.Spec.InstallNamespace, nil
160165
})
166+
coreClient, err := corev1client.NewForConfig(mgr.GetConfig())
167+
if err != nil {
168+
setupLog.Error(err, "unable to create core client")
169+
os.Exit(1)
170+
}
171+
tokenGetter := authentication.NewTokenGetter(coreClient, authentication.WithExpirationDuration(1*time.Hour))
172+
173+
restConfigMapper := func(ctx context.Context, o client.Object, c *rest.Config) (*rest.Config, error) {
174+
cExt, ok := o.(*ocv1alpha1.ClusterExtension)
175+
if !ok {
176+
return c, nil
177+
}
178+
namespacedName := types.NamespacedName{
179+
Name: cExt.Spec.ServiceAccount.Name,
180+
Namespace: cExt.Spec.InstallNamespace,
181+
}
182+
token, err := tokenGetter.Get(ctx, namespacedName)
183+
if err != nil {
184+
return nil, fmt.Errorf("failed to extract SA token, %w", err)
185+
}
186+
tempConfig := rest.AnonymousClientConfig(c)
187+
tempConfig.BearerToken = token
188+
return tempConfig, nil
189+
}
161190
cfgGetter, err := helmclient.NewActionConfigGetter(mgr.GetConfig(), mgr.GetRESTMapper(),
162191
helmclient.StorageNamespaceMapper(installNamespaceMapper),
163192
helmclient.ClientNamespaceMapper(installNamespaceMapper),
193+
helmclient.RestConfigMapper(restConfigMapper),
164194
)
165195
if err != nil {
166196
setupLog.Error(err, "unable to config for creating helm client")

config/base/rbac/role.yaml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ metadata:
55
name: manager-role
66
rules:
77
- apiGroups:
8-
- '*'
8+
- apiextensions.k8s.io
99
resources:
10-
- '*'
10+
- customresourcedefinitions
1111
verbs:
12-
- '*'
12+
- get
1313
- apiGroups:
1414
- catalogd.operatorframework.io
1515
resources:
@@ -36,13 +36,21 @@ rules:
3636
- patch
3737
- update
3838
- watch
39+
- apiGroups:
40+
- ""
41+
resources:
42+
- serviceaccounts/token
43+
verbs:
44+
- create
3945
- apiGroups:
4046
- olm.operatorframework.io
4147
resources:
4248
- clusterextensions
4349
verbs:
4450
- get
4551
- list
52+
- patch
53+
- update
4654
- watch
4755
- apiGroups:
4856
- olm.operatorframework.io

config/samples/olm_v1alpha1_clusterextension.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ spec:
77
packageName: argocd-operator
88
version: 0.6.0
99
serviceAccount:
10-
name: argocd-installer
10+
name: default

hack/test/pre-upgrade-setup.sh

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,42 @@ spec:
3333
insecureSkipTLSVerify: true
3434
EOF
3535

36+
kubectl apply -f - <<EOF
37+
apiVersion: v1
38+
kind: ServiceAccount
39+
metadata:
40+
name: upgrade-e2e
41+
namespace: default
42+
EOF
43+
44+
kubectl apply -f - <<EOF
45+
apiVersion: rbac.authorization.k8s.io/v1
46+
kind: ClusterRole
47+
metadata:
48+
name: upgrade-e2e
49+
rules:
50+
- apiGroups:
51+
- "*"
52+
resources:
53+
- "*"
54+
verbs:
55+
- "*"
56+
EOF
57+
58+
kubectl apply -f - <<EOF
59+
apiVersion: rbac.authorization.k8s.io/v1
60+
kind: ClusterRoleBinding
61+
metadata:
62+
name: upgrade-e2e
63+
subjects:
64+
- kind: ServiceAccount
65+
name: upgrade-e2e
66+
namespace: default
67+
roleRef:
68+
apiGroup: rbac.authorization.k8s.io
69+
kind: ClusterRole
70+
name: upgrade-e2e
71+
EOF
3672

3773
kubectl apply -f - << EOF
3874
apiVersion: olm.operatorframework.io/v1alpha1
@@ -44,7 +80,7 @@ spec:
4480
packageName: prometheus
4581
version: 1.0.0
4682
serviceAccount:
47-
name: default
83+
name: upgrade-e2e
4884
EOF
4985

5086
kubectl wait --for=condition=Unpacked --timeout=60s ClusterCatalog $TEST_CLUSTER_CATALOG_NAME

internal/controllers/clusterextension_controller.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,12 @@ type Preflight interface {
112112
Upgrade(context.Context, *release.Release) error
113113
}
114114

115-
//+kubebuilder:rbac:groups=olm.operatorframework.io,resources=clusterextensions,verbs=get;list;watch
115+
//+kubebuilder:rbac:groups=olm.operatorframework.io,resources=clusterextensions,verbs=get;list;watch;update;patch
116116
//+kubebuilder:rbac:groups=olm.operatorframework.io,resources=clusterextensions/status,verbs=update;patch
117117
//+kubebuilder:rbac:groups=olm.operatorframework.io,resources=clusterextensions/finalizers,verbs=update
118118
//+kubebuilder:rbac:groups=core,resources=secrets,verbs=create;update;patch;delete;get;list;watch
119-
//+kubebuilder:rbac:groups=*,resources=*,verbs=*
119+
//+kubebuilder:rbac:groups=core,resources=serviceaccounts/token,verbs=create
120+
//+kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions,verbs=get
120121

121122
//+kubebuilder:rbac:groups=catalogd.operatorframework.io,resources=clustercatalogs,verbs=list;watch
122123
//+kubebuilder:rbac:groups=catalogd.operatorframework.io,resources=catalogmetadata,verbs=list;watch

test/e2e/cluster_extension_install_test.go

Lines changed: 94 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"gopkg.in/yaml.v2"
1717
appsv1 "k8s.io/api/apps/v1"
1818
corev1 "k8s.io/api/core/v1"
19+
rbacv1 "k8s.io/api/rbac/v1"
1920
"k8s.io/apimachinery/pkg/api/errors"
2021
apimeta "k8s.io/apimachinery/pkg/api/meta"
2122
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -38,7 +39,65 @@ const (
3839
var pollDuration = time.Minute
3940
var pollInterval = time.Second
4041

41-
func testInit(t *testing.T) (*ocv1alpha1.ClusterExtension, *catalogd.ClusterCatalog) {
42+
func createServiceAccount(ctx context.Context, name types.NamespacedName) (*corev1.ServiceAccount, error) {
43+
sa := &corev1.ServiceAccount{
44+
ObjectMeta: metav1.ObjectMeta{
45+
Name: name.Name,
46+
Namespace: name.Namespace,
47+
},
48+
}
49+
err := c.Create(ctx, sa)
50+
if err != nil {
51+
return nil, err
52+
}
53+
cr := &rbacv1.ClusterRole{
54+
ObjectMeta: metav1.ObjectMeta{
55+
Name: name.Name,
56+
},
57+
Rules: []rbacv1.PolicyRule{
58+
{
59+
APIGroups: []string{
60+
"*",
61+
},
62+
Resources: []string{
63+
"*",
64+
},
65+
Verbs: []string{
66+
"*",
67+
},
68+
},
69+
},
70+
}
71+
err = c.Create(ctx, cr)
72+
if err != nil {
73+
return nil, err
74+
}
75+
crb := &rbacv1.ClusterRoleBinding{
76+
ObjectMeta: metav1.ObjectMeta{
77+
Name: name.Name,
78+
},
79+
Subjects: []rbacv1.Subject{
80+
{
81+
Kind: "ServiceAccount",
82+
Name: name.Name,
83+
Namespace: name.Namespace,
84+
},
85+
},
86+
RoleRef: rbacv1.RoleRef{
87+
APIGroup: "rbac.authorization.k8s.io",
88+
Kind: "ClusterRole",
89+
Name: name.Name,
90+
},
91+
}
92+
err = c.Create(ctx, crb)
93+
if err != nil {
94+
return nil, err
95+
}
96+
97+
return sa, nil
98+
}
99+
100+
func testInit(t *testing.T) (*ocv1alpha1.ClusterExtension, *catalogd.ClusterCatalog, *corev1.ServiceAccount) {
42101
var err error
43102
extensionCatalog, err := createTestCatalog(context.Background(), testCatalogName, os.Getenv(testCatalogRefEnvVar))
44103
require.NoError(t, err)
@@ -49,10 +108,18 @@ func testInit(t *testing.T) (*ocv1alpha1.ClusterExtension, *catalogd.ClusterCata
49108
Name: clusterExtensionName,
50109
},
51110
}
52-
return clusterExtension, extensionCatalog
111+
112+
defaultNamespace := types.NamespacedName{
113+
Name: clusterExtensionName,
114+
Namespace: "default",
115+
}
116+
117+
sa, err := createServiceAccount(context.Background(), defaultNamespace)
118+
require.NoError(t, err)
119+
return clusterExtension, extensionCatalog, sa
53120
}
54121

55-
func testCleanup(t *testing.T, cat *catalogd.ClusterCatalog, clusterExtension *ocv1alpha1.ClusterExtension) {
122+
func testCleanup(t *testing.T, cat *catalogd.ClusterCatalog, clusterExtension *ocv1alpha1.ClusterExtension, sa *corev1.ServiceAccount) {
56123
require.NoError(t, c.Delete(context.Background(), cat))
57124
require.Eventually(t, func() bool {
58125
err := c.Get(context.Background(), types.NamespacedName{Name: cat.Name}, &catalogd.ClusterCatalog{})
@@ -63,21 +130,26 @@ func testCleanup(t *testing.T, cat *catalogd.ClusterCatalog, clusterExtension *o
63130
err := c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, &ocv1alpha1.ClusterExtension{})
64131
return errors.IsNotFound(err)
65132
}, pollDuration, pollInterval)
133+
require.NoError(t, c.Delete(context.Background(), sa))
134+
require.Eventually(t, func() bool {
135+
err := c.Get(context.Background(), types.NamespacedName{Name: sa.Name, Namespace: sa.Namespace}, &corev1.ServiceAccount{})
136+
return errors.IsNotFound(err)
137+
}, pollDuration, pollInterval)
66138
}
67139

68140
func TestClusterExtensionInstallRegistry(t *testing.T) {
69141
t.Log("When a cluster extension is installed from a catalog")
70142
t.Log("When the extension bundle format is registry+v1")
71143

72-
clusterExtension, extensionCatalog := testInit(t)
73-
defer testCleanup(t, extensionCatalog, clusterExtension)
144+
clusterExtension, extensionCatalog, sa := testInit(t)
145+
defer testCleanup(t, extensionCatalog, clusterExtension, sa)
74146
defer getArtifactsOutput(t)
75147

76148
clusterExtension.Spec = ocv1alpha1.ClusterExtensionSpec{
77149
PackageName: "prometheus",
78150
InstallNamespace: "default",
79151
ServiceAccount: ocv1alpha1.ServiceAccountReference{
80-
Name: "default",
152+
Name: sa.Name,
81153
},
82154
}
83155
t.Log("It resolves the specified package with correct bundle path")
@@ -128,8 +200,8 @@ func TestClusterExtensionBlockInstallNonSuccessorVersion(t *testing.T) {
128200
t.Log("When a cluster extension is installed from a catalog")
129201
t.Log("When resolving upgrade edges")
130202

131-
clusterExtension, extensionCatalog := testInit(t)
132-
defer testCleanup(t, extensionCatalog, clusterExtension)
203+
clusterExtension, extensionCatalog, sa := testInit(t)
204+
defer testCleanup(t, extensionCatalog, clusterExtension, sa)
133205
defer getArtifactsOutput(t)
134206

135207
t.Log("By creating an ClusterExtension at a specified version")
@@ -138,7 +210,7 @@ func TestClusterExtensionBlockInstallNonSuccessorVersion(t *testing.T) {
138210
Version: "1.0.0",
139211
InstallNamespace: "default",
140212
ServiceAccount: ocv1alpha1.ServiceAccountReference{
141-
Name: "default",
213+
Name: sa.Name,
142214
},
143215
}
144216
require.NoError(t, c.Create(context.Background(), clusterExtension))
@@ -177,8 +249,8 @@ func TestClusterExtensionForceInstallNonSuccessorVersion(t *testing.T) {
177249
t.Log("When a cluster extension is installed from a catalog")
178250
t.Log("When resolving upgrade edges")
179251

180-
clusterExtension, extensionCatalog := testInit(t)
181-
defer testCleanup(t, extensionCatalog, clusterExtension)
252+
clusterExtension, extensionCatalog, sa := testInit(t)
253+
defer testCleanup(t, extensionCatalog, clusterExtension, sa)
182254
defer getArtifactsOutput(t)
183255

184256
t.Log("By creating an ClusterExtension at a specified version")
@@ -187,7 +259,7 @@ func TestClusterExtensionForceInstallNonSuccessorVersion(t *testing.T) {
187259
Version: "1.0.0",
188260
InstallNamespace: "default",
189261
ServiceAccount: ocv1alpha1.ServiceAccountReference{
190-
Name: "default",
262+
Name: sa.Name,
191263
},
192264
}
193265
require.NoError(t, c.Create(context.Background(), clusterExtension))
@@ -225,8 +297,8 @@ func TestClusterExtensionForceInstallNonSuccessorVersion(t *testing.T) {
225297
func TestClusterExtensionInstallSuccessorVersion(t *testing.T) {
226298
t.Log("When a cluster extension is installed from a catalog")
227299
t.Log("When resolving upgrade edges")
228-
clusterExtension, extensionCatalog := testInit(t)
229-
defer testCleanup(t, extensionCatalog, clusterExtension)
300+
clusterExtension, extensionCatalog, sa := testInit(t)
301+
defer testCleanup(t, extensionCatalog, clusterExtension, sa)
230302
defer getArtifactsOutput(t)
231303

232304
t.Log("By creating an ClusterExtension at a specified version")
@@ -235,7 +307,7 @@ func TestClusterExtensionInstallSuccessorVersion(t *testing.T) {
235307
Version: "1.0.0",
236308
InstallNamespace: "default",
237309
ServiceAccount: ocv1alpha1.ServiceAccountReference{
238-
Name: "default",
310+
Name: sa.Name,
239311
},
240312
}
241313
require.NoError(t, c.Create(context.Background(), clusterExtension))
@@ -272,15 +344,15 @@ func TestClusterExtensionInstallSuccessorVersion(t *testing.T) {
272344
func TestClusterExtensionInstallReResolvesWhenCatalogIsPatched(t *testing.T) {
273345
t.Log("When a cluster extension is installed from a catalog")
274346
t.Log("It resolves again when a catalog is patched with new ImageRef")
275-
clusterExtension, extensionCatalog := testInit(t)
276-
defer testCleanup(t, extensionCatalog, clusterExtension)
347+
clusterExtension, extensionCatalog, sa := testInit(t)
348+
defer testCleanup(t, extensionCatalog, clusterExtension, sa)
277349
defer getArtifactsOutput(t)
278350

279351
clusterExtension.Spec = ocv1alpha1.ClusterExtensionSpec{
280352
PackageName: "prometheus",
281353
InstallNamespace: "default",
282354
ServiceAccount: ocv1alpha1.ServiceAccountReference{
283-
Name: "default",
355+
Name: sa.Name,
284356
},
285357
}
286358
t.Log("It resolves the specified package with correct bundle path")
@@ -351,14 +423,16 @@ func TestClusterExtensionInstallReResolvesWhenNewCatalog(t *testing.T) {
351423
Name: clusterExtensionName,
352424
},
353425
}
354-
defer testCleanup(t, extensionCatalog, clusterExtension)
426+
sa, err := createServiceAccount(context.Background(), types.NamespacedName{Name: clusterExtensionName, Namespace: "default"})
427+
require.NoError(t, err)
428+
defer testCleanup(t, extensionCatalog, clusterExtension, sa)
355429
defer getArtifactsOutput(t)
356430

357431
clusterExtension.Spec = ocv1alpha1.ClusterExtensionSpec{
358432
PackageName: "prometheus",
359433
InstallNamespace: "default",
360434
ServiceAccount: ocv1alpha1.ServiceAccountReference{
361-
Name: "default",
435+
Name: sa.Name,
362436
},
363437
}
364438
t.Log("It resolves the specified package with correct bundle path")

0 commit comments

Comments
 (0)