Skip to content

Commit

Permalink
add: project scope support for clusters (#143)
Browse files Browse the repository at this point in the history
* tests: add precheck function for feature support

Useful for acceptance tests that should only be run when specific
features are supported by ArgoCD version.
If a feature is not supported the test is skipped, not failed.
For local testing, you now have to add the `ARGOCD_VERSION` environment variable until a better long-term solution is found.

* add: project scope support for clusters
  • Loading branch information
alxbse authored Feb 25, 2022
1 parent 618ceb4 commit 647debc
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,6 @@ jobs:
netstat -tulpn
- name: Run acceptance tests
env:
ARGOCD_VERSION: ${{ matrix.argocd_version }}
run: sh scripts/testacc.sh
2 changes: 2 additions & 0 deletions argocd/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (
featureIgnoreDiffJQPathExpressions
featureRepositoryGet
featureTokenIDs
featureProjectScopedClusters
)

var (
Expand All @@ -31,6 +32,7 @@ var (
featureIgnoreDiffJQPathExpressions: semver.MustParse("2.1.0"),
featureRepositoryGet: semver.MustParse("1.6.0"),
featureTokenIDs: semver.MustParse("1.5.3"),
featureProjectScopedClusters: semver.MustParse("2.2.0"),
}
)

Expand Down
19 changes: 19 additions & 0 deletions argocd/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"os"
"testing"

"github.com/Masterminds/semver"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

Expand Down Expand Up @@ -41,3 +42,21 @@ func testAccPreCheck(t *testing.T) {
t.Fatal("ARGOCD_INSECURE should be set for acceptance tests")
}
}

func testAccPreCheckFeatureSupported(t *testing.T, feature int) {
v := os.Getenv("ARGOCD_VERSION")
if v == "" {
t.Skip("ARGOCD_VERSION must be set set for feature supported acceptance tests")
}
serverVersion, err := semver.NewVersion(v)
if err != nil {
t.Fatalf("could not parse ARGOCD_VERSION as semantic version: %s", v)
}
versionConstraint, ok := featureVersionConstraintsMap[feature]
if !ok {
t.Fatal("feature constraint is not handled by the provider")
}
if i := versionConstraint.Compare(serverVersion); i == 1 {
t.Skipf("version %s does not support feature", v)
}
}
46 changes: 46 additions & 0 deletions argocd/resource_argocd_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,29 @@ func resourceArgoCDClusterCreate(ctx context.Context, d *schema.ResourceData, me
}

}

featureProjectScopedClustersSupported, err := server.isFeatureSupported(featureProjectScopedClusters)
if err != nil {
return []diag.Diagnostic{
{
Severity: diag.Error,
Summary: "feature not supported",
Detail: err.Error(),
},
}
}
if !featureProjectScopedClustersSupported && cluster.Project != "" {
return []diag.Diagnostic{
{
Severity: diag.Error,
Summary: fmt.Sprintf(
"cluster project is only supported from ArgoCD %s onwards",
featureVersionConstraintsMap[featureProjectScopedClusters].String()),
Detail: "See https://argo-cd.readthedocs.io/en/stable/user-guide/projects/#project-scoped-repositories-and-clusters",
},
}
}

c, err := client.Create(ctx, &clusterClient.ClusterCreateRequest{
Cluster: cluster, Upsert: true})
if err != nil {
Expand Down Expand Up @@ -128,6 +151,29 @@ func resourceArgoCDClusterUpdate(ctx context.Context, d *schema.ResourceData, me
},
}
}

featureProjectScopedClustersSupported, err := server.isFeatureSupported(featureProjectScopedClusters)
if err != nil {
return []diag.Diagnostic{
{
Severity: diag.Error,
Summary: "feature not supported",
Detail: err.Error(),
},
}
}
if !featureProjectScopedClustersSupported && cluster.Project != "" {
return []diag.Diagnostic{
{
Severity: diag.Error,
Summary: fmt.Sprintf(
"cluster project is only supported from ArgoCD %s onwards",
featureVersionConstraintsMap[featureProjectScopedClusters].String()),
Detail: "See https://argo-cd.readthedocs.io/en/stable/user-guide/projects/#project-scoped-repositories-and-clusters",
},
}
}

_, err = client.Update(ctx, &clusterClient.ClusterUpdateRequest{Cluster: cluster})
if err != nil {
if strings.Contains(err.Error(), "NotFound") {
Expand Down
46 changes: 46 additions & 0 deletions argocd/resource_argocd_cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,35 @@ func TestAccArgoCDCluster(t *testing.T) {
})
}

func TestAccArgoCDCluster_projectScope(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t); testAccPreCheckFeatureSupported(t, featureProjectScopedClusters) },
ProviderFactories: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccArgoCDClusterProjectScope(acctest.RandString(10), "myproject1"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"argocd_cluster.project_scope",
"info.0.connection_state.0.status",
"Successful",
),
resource.TestCheckResourceAttr(
"argocd_cluster.project_scope",
"config.0.tls_client_config.0.insecure",
"true",
),
resource.TestCheckResourceAttr(
"argocd_cluster.project_scope",
"project",
"myproject1",
),
),
},
},
})
}

func testAccArgoCDClusterBearerToken(clusterName string) string {
return fmt.Sprintf(`
resource "argocd_cluster" "simple" {
Expand Down Expand Up @@ -118,6 +147,23 @@ EOT
`, clusterName, rc.KeyData, rc.CertData, rc.CAData, rc.ServerName)
}

func testAccArgoCDClusterProjectScope(clusterName, projectName string) string {
return fmt.Sprintf(`
resource "argocd_cluster" "project_scope" {
server = "https://kubernetes.default.svc.cluster.local"
name = "%s"
project = "%s"
config {
# Uses Kind's bootstrap token whose ttl is 24 hours after cluster bootstrap.
bearer_token = "abcdef.0123456789abcdef"
tls_client_config {
insecure = true
}
}
}
`, clusterName, projectName)
}

// getInternalRestConfig returns the internal Kubernetes cluster REST config.
func getInternalRestConfig() (*rest.Config, error) {
rc := &rest.Config{}
Expand Down
5 changes: 5 additions & 0 deletions argocd/schema_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,5 +205,10 @@ func clusterSchema() map[string]*schema.Schema {
},
},
},
"project": {
Type: schema.TypeString,
Description: "Add cluster scoped to project",
Optional: true,
},
}
}
5 changes: 5 additions & 0 deletions argocd/structure_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ func expandCluster(d *schema.ResourceData) (*application.Cluster, error) {
cluster.Annotations = m.Annotations
cluster.Labels = m.Labels

if v, ok := d.GetOk("project"); ok {
cluster.Project = v.(string)
}

return cluster, err
}

Expand Down Expand Up @@ -113,6 +117,7 @@ func flattenCluster(cluster *application.Cluster, d *schema.ResourceData) error
"namespaces": cluster.Namespaces,
"info": flattenClusterInfo(cluster.Info),
"config": flattenClusterConfig(cluster.Config, d),
"project": cluster.Project,
}
if cluster.Shard != nil {
r["shard"] = convertInt64PointerToString(cluster.Shard)
Expand Down
1 change: 1 addition & 0 deletions docs/resources/cluster.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ resource "argocd_cluster" "eks" {
* `namespaces` - (Optional) Holds list of namespaces which are accessible in that cluster. Cluster level resources would be ignored if namespace list is not empty..
* `config` - (Optional) The configuration specification, nested attributes are documented below.
* `metadata` - (Optional) Cluster metadata, nested attributes are documented below.
* `project` - (Optional) Scope cluster to ArgoCD project. If omitted, cluster will be global. Requires ArgoCD 2.2.0 onwards.

The `config` block can have the following attributes:

Expand Down

0 comments on commit 647debc

Please sign in to comment.