Skip to content

Commit 740629d

Browse files
nimjorJordan Nimlosthe-technatJordan Nimlosblakepettersson
authored
feat: Add support for destination service accounts (#567)
* upgrade argo version and add support for dest svc accts Signed-off-by: Jordan Nimlos <[email protected]> * feat(tests): align workflow file with framework skaffold repo (#563) Signed-off-by: Nathanael Liechti <[email protected]> Signed-off-by: Jordan Nimlos <[email protected]> * feat: align tools folder with scaffold repo (#565) Signed-off-by: Nathanael Liechti <[email protected]> Signed-off-by: Jordan Nimlos <[email protected]> * include flattener function for dsa Signed-off-by: Jordan Nimlos <[email protected]> * add updated docs Signed-off-by: Jordan Nimlos <[email protected]> * go mod tidy and fix generate/build Signed-off-by: Jordan Nimlos <[email protected]> * add argocd settings api client Signed-off-by: Jordan Nimlos <[email protected]> * add settings check to feature constraints Signed-off-by: Jordan Nimlos <[email protected]> * separate version and settings support checks with a single wrapper Signed-off-by: Jordan Nimlos <[email protected]> * fix linting issues Signed-off-by: Jordan Nimlos <[email protected]> * chore: add ability to optionally filter tests (#684) In the various `Makefile` tasks, add an option to filter out tests if necessary. I also fixed a few tests which were failing when running unit tests where the config params require a k8s environment to be up and running. Signed-off-by: Blake Pettersson <[email protected]> Signed-off-by: Jordan Nimlos <[email protected]> * fix(deps): update module github.com/argoproj/argo-cd/v3 to v3.0.11 (#664) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Signed-off-by: Jordan Nimlos <[email protected]> * chore: migrate to terraform-plugin-testing (#687) * chore: migrate to terraform-plugin-testing It gets pretty messy trying to mix `terraform-plugin-testing` with the older `terraform-plugin-sdk` testing framework, so let's just use `terraform-plugin-testing` for both the old resources as well as the new ones. Signed-off-by: Blake Pettersson <[email protected]> * chore: ignore fields Signed-off-by: Blake Pettersson <[email protected]> --------- Signed-off-by: Blake Pettersson <[email protected]> Signed-off-by: Jordan Nimlos <[email protected]> * add doc comments to IsVersionSupported and IsSettingSupported funcs Signed-off-by: Jordan Nimlos <[email protected]> * separate unstable feature acceptance tests from stable ones Signed-off-by: Jordan Nimlos <[email protected]> * re-add dropped ApplicationSourceName feature Signed-off-by: Jordan Nimlos <[email protected]> * revert unstable feature test workflows Signed-off-by: Jordan Nimlos <[email protected]> * revert feature constraint server settings component Signed-off-by: Jordan Nimlos <[email protected]> * missed cleanup IsVersionSupported func, add nil check on fc.MinVersion Signed-off-by: Jordan Nimlos <[email protected]> * avoid panic in expandDestinationServiceAccounts Signed-off-by: Jordan Nimlos <[email protected]> * rm kubernetes tf provider usage in test Signed-off-by: Jordan Nimlos <[email protected]> * check feature support on resource create/update Signed-off-by: Jordan Nimlos <[email protected]> * add fc.MinVersion nil check to new server_interface Signed-off-by: Jordan Nimlos <[email protected]> --------- Signed-off-by: Jordan Nimlos <[email protected]> Signed-off-by: Nathanael Liechti <[email protected]> Signed-off-by: nimjor <[email protected]> Signed-off-by: Blake Pettersson <[email protected]> Co-authored-by: Jordan Nimlos <[email protected]> Co-authored-by: Nathanael Liechti <[email protected]> Co-authored-by: Jordan Nimlos <[email protected]> Co-authored-by: Blake Pettersson <[email protected]> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
1 parent bc2aeab commit 740629d

File tree

8 files changed

+175
-1
lines changed

8 files changed

+175
-1
lines changed

argocd/resource_argocd_project.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ func resourceArgoCDProjectCreate(ctx context.Context, d *schema.ResourceData, me
6464
}
6565
}
6666

67+
if !si.IsFeatureSupported(features.ProjectDestinationServiceAccounts) {
68+
_, destinationServiceAccountsOk := d.GetOk("spec.0.destination_service_account")
69+
if destinationServiceAccountsOk {
70+
return featureNotSupported(features.ProjectDestinationServiceAccounts)
71+
}
72+
}
73+
6774
if _, ok := tokenMutexProjectMap[projectName]; !ok {
6875
tokenMutexProjectMap[projectName] = &sync.RWMutex{}
6976
}
@@ -170,6 +177,13 @@ func resourceArgoCDProjectUpdate(ctx context.Context, d *schema.ResourceData, me
170177
}
171178
}
172179

180+
if !si.IsFeatureSupported(features.ProjectDestinationServiceAccounts) {
181+
_, destinationServiceAccountsOk := d.GetOk("spec.0.destination_service_account")
182+
if destinationServiceAccountsOk {
183+
return featureNotSupported(features.ProjectDestinationServiceAccounts)
184+
}
185+
}
186+
173187
projectName := objectMeta.Name
174188

175189
if _, ok := tokenMutexProjectMap[projectName]; !ok {

argocd/resource_argocd_project_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,44 @@ func TestAccArgoCDProjectWithSourceNamespaces(t *testing.T) {
254254
})
255255
}
256256

257+
func TestAccArgoCDProjectWithDestinationServiceAccounts(t *testing.T) {
258+
name := acctest.RandomWithPrefix("test-acc")
259+
260+
resource.Test(t, resource.TestCase{
261+
PreCheck: func() {
262+
testAccPreCheck(t)
263+
testAccPreCheckFeatureSupported(t, features.ProjectDestinationServiceAccounts)
264+
},
265+
ProviderFactories: testAccProviders,
266+
Steps: []resource.TestStep{
267+
{
268+
Config: testAccArgoCDProjectWithDestinationServiceAccounts(name),
269+
Check: resource.ComposeTestCheckFunc(
270+
resource.TestCheckResourceAttrSet(
271+
"argocd_project.simple",
272+
"metadata.0.uid",
273+
),
274+
resource.TestCheckResourceAttr(
275+
"argocd_project.simple",
276+
"spec.0.destination_service_account.0.default_service_account",
277+
"default",
278+
),
279+
resource.TestCheckResourceAttr(
280+
"argocd_project.simple",
281+
"spec.0.destination_service_account.1.default_service_account",
282+
"foo",
283+
),
284+
),
285+
},
286+
{
287+
ResourceName: "argocd_project.simple",
288+
ImportState: true,
289+
ImportStateVerify: true,
290+
},
291+
},
292+
})
293+
}
294+
257295
func TestAccArgoCDProjectWithFineGrainedPolicy(t *testing.T) {
258296
name := acctest.RandomWithPrefix("test-acc")
259297

@@ -860,6 +898,47 @@ resource "argocd_project" "failure" {
860898
`, name, name, name)
861899
}
862900

901+
func testAccArgoCDProjectWithDestinationServiceAccounts(name string) string {
902+
return fmt.Sprintf(`
903+
resource "argocd_project" "simple" {
904+
metadata {
905+
name = "%s"
906+
namespace = "argocd"
907+
labels = {
908+
acceptance = "true"
909+
}
910+
annotations = {
911+
"this.is.a.really.long.nested.key" = "yes, really!"
912+
}
913+
}
914+
915+
spec {
916+
description = "simple"
917+
source_repos = ["*"]
918+
919+
destination {
920+
server = "https://kubernetes.default.svc"
921+
namespace = "default"
922+
}
923+
destination {
924+
server = "https://kubernetes.default.svc"
925+
namespace = "foo"
926+
}
927+
destination_service_account {
928+
default_service_account = "default"
929+
namespace = "default"
930+
server = "https://kubernetes.default.svc"
931+
}
932+
destination_service_account {
933+
default_service_account = "foo"
934+
namespace = "foo"
935+
server = "https://kubernetes.default.svc"
936+
}
937+
}
938+
}
939+
`, name)
940+
}
941+
863942
func testAccArgoCDProjectWithFineGrainedPolicy(name string) string {
864943
return fmt.Sprintf(`
865944
resource "argocd_project" "fine_grained_policy" {

argocd/schema_project.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,30 @@ func projectSpecSchemaV2() *schema.Schema {
488488
},
489489
},
490490
},
491+
"destination_service_account": {
492+
Type: schema.TypeSet,
493+
Description: "Service accounts to be impersonated for the application sync operation for each destination.",
494+
Optional: true,
495+
Elem: &schema.Resource{
496+
Schema: map[string]*schema.Schema{
497+
"default_service_account": {
498+
Type: schema.TypeString,
499+
Description: "Used for impersonation during the sync operation",
500+
Required: true,
501+
},
502+
"namespace": {
503+
Type: schema.TypeString,
504+
Description: "Specifies the target namespace for the application's resources.",
505+
Optional: true,
506+
},
507+
"server": {
508+
Type: schema.TypeString,
509+
Description: "Specifies the URL of the target cluster's Kubernetes control plane API.",
510+
Required: true,
511+
},
512+
},
513+
},
514+
},
491515
"namespace_resource_blacklist": {
492516
Type: schema.TypeSet,
493517
Description: "Blacklisted namespace level resources.",

argocd/server_interface.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ func (si *ServerInterface) InitClients(ctx context.Context) diag.Diagnostics {
164164
func (si *ServerInterface) IsFeatureSupported(feature features.Feature) bool {
165165
fc, ok := features.ConstraintsMap[feature]
166166

167+
if fc.MinVersion == nil {
168+
return true
169+
}
170+
167171
return ok && fc.MinVersion.Compare(si.ServerVersion) != 1
168172
}
169173

argocd/structure_project.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ func expandProjectSpec(d *schema.ResourceData) (spec application.AppProjectSpec,
104104
spec.Destinations = expandApplicationDestinations(v.(*schema.Set))
105105
}
106106

107+
if v, ok := s["destination_service_account"]; ok {
108+
spec.DestinationServiceAccounts = expandDestinationServiceAccounts(v.(*schema.Set))
109+
}
110+
107111
if v, ok := s["sync_window"]; ok {
108112
spec.SyncWindows = expandSyncWindows(v.([]interface{}))
109113
}
@@ -123,6 +127,20 @@ func expandProjectSpec(d *schema.ResourceData) (spec application.AppProjectSpec,
123127
return spec, nil
124128
}
125129

130+
func expandDestinationServiceAccounts(dsas *schema.Set) (result []application.ApplicationDestinationServiceAccount) {
131+
for _, _dsa := range dsas.List() {
132+
dsa := _dsa.(map[string]interface{})
133+
134+
result = append(result, application.ApplicationDestinationServiceAccount{
135+
DefaultServiceAccount: dsa["default_service_account"].(string),
136+
Namespace: dsa["namespace"].(string),
137+
Server: dsa["server"].(string),
138+
})
139+
}
140+
141+
return
142+
}
143+
126144
func expandOrphanedResourcesIgnore(ignore *schema.Set) (result []application.OrphanedResourceKey) {
127145
for _, _i := range ignore.List() {
128146
i := _i.(map[string]interface{})
@@ -161,6 +179,7 @@ func flattenProjectSpec(s application.AppProjectSpec) []map[string]interface{} {
161179
"namespace_resource_blacklist": flattenK8SGroupKinds(s.NamespaceResourceBlacklist),
162180
"namespace_resource_whitelist": flattenK8SGroupKinds(s.NamespaceResourceWhitelist),
163181
"destination": flattenApplicationDestinations(s.Destinations),
182+
"destination_service_account": flattenProjectDestinationServiceAccounts(s.DestinationServiceAccounts),
164183
"orphaned_resources": flattenProjectOrphanedResources(s.OrphanedResources),
165184
"role": flattenProjectRoles(s.Roles),
166185
"sync_window": flattenSyncWindows(s.SyncWindows),
@@ -223,3 +242,15 @@ func flattenProjectRoles(rs []application.ProjectRole) (result []map[string]inte
223242

224243
return
225244
}
245+
246+
func flattenProjectDestinationServiceAccounts(dsas []application.ApplicationDestinationServiceAccount) (result []map[string]string) {
247+
for _, dsa := range dsas {
248+
result = append(result, map[string]string{
249+
"default_service_account": dsa.DefaultServiceAccount,
250+
"namespace": dsa.Namespace,
251+
"server": dsa.Server,
252+
})
253+
}
254+
255+
return
256+
}

docs/resources/project.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ Optional:
173173
- `cluster_resource_blacklist` (Block Set) Blacklisted cluster level resources. (see [below for nested schema](#nestedblock--spec--cluster_resource_blacklist))
174174
- `cluster_resource_whitelist` (Block Set) Whitelisted cluster level resources. (see [below for nested schema](#nestedblock--spec--cluster_resource_whitelist))
175175
- `description` (String) Project description.
176+
- `destination_service_account` (Block Set) Service accounts to be impersonated for the application sync operation for each destination. (see [below for nested schema](#nestedblock--spec--destination_service_account))
176177
- `namespace_resource_blacklist` (Block Set) Blacklisted namespace level resources. (see [below for nested schema](#nestedblock--spec--namespace_resource_blacklist))
177178
- `namespace_resource_whitelist` (Block Set) Whitelisted namespace level resources. (see [below for nested schema](#nestedblock--spec--namespace_resource_whitelist))
178179
- `orphaned_resources` (Block List, Max: 1) Settings specifying if controller should monitor orphaned resources of apps in this project. (see [below for nested schema](#nestedblock--spec--orphaned_resources))
@@ -212,6 +213,19 @@ Optional:
212213
- `kind` (String) The Kubernetes resource Kind to match for.
213214

214215

216+
<a id="nestedblock--spec--destination_service_account"></a>
217+
### Nested Schema for `spec.destination_service_account`
218+
219+
Required:
220+
221+
- `default_service_account` (String) Used for impersonation during the sync operation
222+
- `server` (String) Specifies the URL of the target cluster's Kubernetes control plane API.
223+
224+
Optional:
225+
226+
- `namespace` (String) Specifies the target namespace for the application's resources.
227+
228+
215229
<a id="nestedblock--spec--namespace_resource_blacklist"></a>
216230
### Nested Schema for `spec.namespace_resource_blacklist`
217231

internal/features/features.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@ const (
1717
ApplicationSetIgnoreApplicationDifferences
1818
ApplicationSetTemplatePatch
1919
ApplicationKustomizePatches
20+
ProjectDestinationServiceAccounts
2021
ProjectFineGrainedPolicy
2122
ApplicationSourceName
2223
)
2324

2425
type FeatureConstraint struct {
25-
Name string
26+
// Name is a human-readable name for the feature.
27+
Name string
28+
// MinVersion is the minimum ArgoCD version that supports this feature.
2629
MinVersion *semver.Version
2730
}
2831

@@ -39,4 +42,5 @@ var ConstraintsMap = map[Feature]FeatureConstraint{
3942
ApplicationKustomizePatches: {"application kustomize patches", semver.MustParse("2.9.0")},
4043
ProjectFineGrainedPolicy: {"fine-grained policy in project", semver.MustParse("2.12.0")},
4144
ApplicationSourceName: {"named application sources", semver.MustParse("2.14.0")},
45+
ProjectDestinationServiceAccounts: {"project destination service accounts", semver.MustParse("2.13.0")},
4246
}

internal/provider/server_interface.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ func (si *ServerInterface) InitClients(ctx context.Context) diag.Diagnostics {
164164
func (si *ServerInterface) IsFeatureSupported(feature features.Feature) bool {
165165
fc, ok := features.ConstraintsMap[feature]
166166

167+
if fc.MinVersion == nil {
168+
return true
169+
}
170+
167171
return ok && fc.MinVersion.Compare(si.ServerVersion) != 1
168172
}
169173

0 commit comments

Comments
 (0)