github.com/argoproj-labs/argocd-operator@v0.10.0/controllers/argocd/service_account_test.go (about)

     1  // Copyright 2019 ArgoCD Operator Developers
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // 	http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package argocd
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"os"
    21  	"testing"
    22  
    23  	"github.com/stretchr/testify/assert"
    24  	corev1 "k8s.io/api/core/v1"
    25  	v1 "k8s.io/api/rbac/v1"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"k8s.io/apimachinery/pkg/types"
    28  	"sigs.k8s.io/controller-runtime/pkg/client"
    29  	logf "sigs.k8s.io/controller-runtime/pkg/log"
    30  
    31  	argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1"
    32  )
    33  
    34  func TestReconcileArgoCD_reconcileServiceAccountPermissions(t *testing.T) {
    35  	logf.SetLogger(ZapLogger(true))
    36  	a := makeTestArgoCD()
    37  
    38  	resObjs := []client.Object{a}
    39  	subresObjs := []client.Object{a}
    40  	runtimeObjs := []runtime.Object{}
    41  	sch := makeTestReconcilerScheme(argoproj.AddToScheme)
    42  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
    43  	r := makeTestReconciler(cl, sch)
    44  
    45  	assert.NoError(t, createNamespace(r, a.Namespace, ""))
    46  
    47  	// objective is to verify if the right rule associations have happened.
    48  
    49  	expectedRules := policyRuleForApplicationController()
    50  	workloadIdentifier := "xrb"
    51  
    52  	assert.NoError(t, r.reconcileServiceAccountPermissions(workloadIdentifier, expectedRules, a))
    53  
    54  	reconciledServiceAccount := &corev1.ServiceAccount{}
    55  	reconciledRole := &v1.Role{}
    56  	reconcileRoleBinding := &v1.RoleBinding{}
    57  	expectedName := fmt.Sprintf("%s-%s", a.Name, workloadIdentifier)
    58  
    59  	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedName, Namespace: a.Namespace}, reconciledRole))
    60  	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedName, Namespace: a.Namespace}, reconcileRoleBinding))
    61  	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedName, Namespace: a.Namespace}, reconciledServiceAccount))
    62  	assert.Equal(t, expectedRules, reconciledRole.Rules)
    63  
    64  	// undesirable changes
    65  	reconciledRole.Rules = policyRuleForRedisHa(r.Client)
    66  	assert.NoError(t, r.Client.Update(context.TODO(), reconciledRole))
    67  
    68  	// fetch it
    69  	dirtyRole := &v1.Role{}
    70  	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedName, Namespace: a.Namespace}, dirtyRole))
    71  	assert.Equal(t, reconciledRole.Rules, dirtyRole.Rules)
    72  
    73  	// Have the reconciler override them
    74  	assert.NoError(t, r.reconcileServiceAccountPermissions(workloadIdentifier, expectedRules, a))
    75  
    76  	// fetch it
    77  	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedName, Namespace: a.Namespace}, reconciledRole))
    78  	assert.Equal(t, expectedRules, reconciledRole.Rules)
    79  }
    80  
    81  func TestReconcileArgoCD_reconcileServiceAccountClusterPermissions(t *testing.T) {
    82  	logf.SetLogger(ZapLogger(true))
    83  	a := makeTestArgoCD()
    84  
    85  	resObjs := []client.Object{a}
    86  	subresObjs := []client.Object{a}
    87  	runtimeObjs := []runtime.Object{}
    88  	sch := makeTestReconcilerScheme(argoproj.AddToScheme)
    89  	cl := makeTestReconcilerClient(sch, resObjs, subresObjs, runtimeObjs)
    90  	r := makeTestReconciler(cl, sch)
    91  
    92  	workloadIdentifier := "xrb"
    93  	expectedClusterRoleBindingName := fmt.Sprintf("%s-%s-%s", a.Name, a.Namespace, workloadIdentifier)
    94  	expectedClusterRoleName := fmt.Sprintf("%s-%s-%s", a.Name, a.Namespace, workloadIdentifier)
    95  	expectedNameSA := fmt.Sprintf("%s-%s", a.Name, workloadIdentifier)
    96  
    97  	reconcileServiceAccount := &corev1.ServiceAccount{}
    98  	reconcileClusterRoleBinding := &v1.ClusterRoleBinding{}
    99  	reconcileClusterRole := &v1.ClusterRole{}
   100  
   101  	//reconcile ServiceAccountClusterPermissions with no policy rules
   102  	assert.NoError(t, r.reconcileServiceAccountClusterPermissions(workloadIdentifier, testRules(), a))
   103  
   104  	//Service account should be created but no ClusterRole/ClusterRoleBinding should be created
   105  	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedNameSA, Namespace: a.Namespace}, reconcileServiceAccount))
   106  	//assert.ErrorContains(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRoleBindingName}, reconcileClusterRoleBinding), "not found")
   107  	//TODO: https://github.com/stretchr/testify/pull/1022 introduced ErrorContains, but is not yet available in a tagged release. Revert to ErrorContains once this becomes available
   108  	assert.Error(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRoleBindingName}, reconcileClusterRoleBinding))
   109  	assert.Contains(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRoleBindingName}, reconcileClusterRoleBinding).Error(), "not found")
   110  	//assert.ErrorContains(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRoleName}, reconcileClusterRole), "not found")
   111  	//TODO: https://github.com/stretchr/testify/pull/1022 introduced ErrorContains, but is not yet available in a tagged release. Revert to ErrorContains once this becomes available
   112  	assert.Error(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRoleName}, reconcileClusterRole))
   113  	assert.Contains(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRoleName}, reconcileClusterRole).Error(), "not found")
   114  
   115  	t.Setenv("ARGOCD_CLUSTER_CONFIG_NAMESPACES", a.Namespace)
   116  
   117  	// objective is to verify if the right SA associations have happened.
   118  	assert.NoError(t, r.reconcileServiceAccountClusterPermissions(workloadIdentifier, testRules(), a))
   119  
   120  	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedNameSA, Namespace: a.Namespace}, reconcileServiceAccount))
   121  	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRoleName}, reconcileClusterRole))
   122  	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRoleBindingName}, reconcileClusterRoleBinding))
   123  
   124  	// undesirable changes
   125  	reconcileClusterRoleBinding.RoleRef.Name = "z"
   126  	reconcileClusterRoleBinding.Subjects[0].Name = "z"
   127  	assert.NoError(t, r.Client.Update(context.TODO(), reconcileClusterRoleBinding))
   128  
   129  	// fetch it
   130  	dirtyClusterRoleBinding := &v1.ClusterRoleBinding{}
   131  	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRoleBindingName}, dirtyClusterRoleBinding))
   132  	assert.Equal(t, reconcileClusterRoleBinding.RoleRef.Name, dirtyClusterRoleBinding.RoleRef.Name)
   133  
   134  	// Have the reconciler override them
   135  	assert.NoError(t, r.reconcileServiceAccountClusterPermissions(workloadIdentifier, testRules(), a))
   136  
   137  	// fetch it
   138  	assert.NoError(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRoleBindingName}, reconcileClusterRoleBinding))
   139  	assert.Equal(t, expectedClusterRoleName, reconcileClusterRoleBinding.RoleRef.Name)
   140  
   141  	// Check if cluster role and rolebinding gets deleted
   142  	os.Unsetenv("ARGOCD_CLUSTER_CONFIG_NAMESPACES")
   143  	assert.NoError(t, r.reconcileServiceAccountClusterPermissions(workloadIdentifier, testRules(), a))
   144  	//assert.ErrorContains(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRoleBindingName}, reconcileClusterRoleBinding), "not found")
   145  	//TODO: https://github.com/stretchr/testify/pull/1022 introduced ErrorContains, but is not yet available in a tagged release. Revert to ErrorContains once this becomes available
   146  	assert.Error(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRoleBindingName}, reconcileClusterRoleBinding))
   147  	assert.Contains(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRoleBindingName}, reconcileClusterRoleBinding).Error(), "not found")
   148  	//assert.ErrorContains(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRoleName}, reconcileClusterRole), "not found")
   149  	//TODO: https://github.com/stretchr/testify/pull/1022 introduced ErrorContains, but is not yet available in a tagged release. Revert to ErrorContains once this becomes available
   150  	assert.Error(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRoleName}, reconcileClusterRole))
   151  	assert.Contains(t, r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRoleName}, reconcileClusterRole).Error(), "not found")
   152  }
   153  
   154  func testRules() []v1.PolicyRule {
   155  	return []v1.PolicyRule{
   156  		{
   157  			APIGroups: []string{
   158  				"*",
   159  			},
   160  			Resources: []string{
   161  				"*",
   162  			},
   163  			Verbs: []string{
   164  				"get",
   165  			},
   166  		},
   167  	}
   168  }