Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support extra parameters in the templates #52

Merged
merged 3 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions api/v1beta1/tenant_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ type TenantSpec struct {
// If not specified, the default controller is used.
// +optional
ControllerName string `json:"controllerName,omitempty"`

// ExtraParams is a map of extra parameters that can be used in the templates.
// +optional
ExtraParams map[string]string `json:"extraParams,omitempty"`
}

// RootNamespaceSpec defines the desired state of Namespace.
Expand Down
7 changes: 7 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions charts/cattage/crds/tenant.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ spec:
- roles
type: object
type: array
extraParams:
additionalProperties:
type: string
description: ExtraParams is a map of extra parameters that can be used in the templates.
type: object
rootNamespaces:
description: RootNamespaces are the list of root namespaces that belong to this tenant.
items:
Expand Down
4 changes: 2 additions & 2 deletions charts/cattage/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ controller:
{{- range .Roles.admin }}
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: {{ . }}
name: {{ .Name }}
{{- end }}
argocd:
namespace: argocd
Expand All @@ -66,7 +66,7 @@ controller:
- groups:
- cybozu-go:{{ .Name }}
{{- range .Roles.admin }}
- cybozu-go:{{ . }}
- cybozu-go:{{ .Name }}
{{- end }}
name: admin
policies:
Expand Down
6 changes: 6 additions & 0 deletions config/crd/bases/cattage.cybozu.io_tenants.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ spec:
- roles
type: object
type: array
extraParams:
additionalProperties:
type: string
description: ExtraParams is a map of extra parameters that can be
used in the templates.
type: object
rootNamespaces:
description: RootNamespaces are the list of root namespaces that belong
to this tenant.
Expand Down
8 changes: 4 additions & 4 deletions config/manager/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ data:
{{- range .Roles.admin }}
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: {{ . }}
name: {{ .Name }}
- kind: ServiceAccount
name: node-{{ . }}
name: node-{{ .Name }}
namespace: teleport
{{- end }}
argocd:
Expand All @@ -48,9 +48,9 @@ data:
kind: LimitRange
roles:
- groups:
- cybozu-go:{{ .Name }}
- cybozu-go:{{with .ExtraParams.GitHubTeam}}{{ . }}{{else}}{{ .Name }}{{end}}
{{- range .Roles.admin }}
- cybozu-go:{{ . }}
- cybozu-go:{{with .ExtraParams.GitHubTeam}}{{ . }}{{else}}{{ .Name }}{{end}}
{{- end }}
name: admin
policies:
Expand Down
4 changes: 4 additions & 0 deletions config/samples/tenant.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ spec:
rootNamespaces:
- name: app-a
controllerName: second
extraParams:
GitHubTeam: a-team-gh
---
apiVersion: cattage.cybozu.io/v1beta1
kind: Tenant
Expand All @@ -21,3 +23,5 @@ spec:
- name: a-team
roles:
- admin
extraParams:
GitHubTeam: b-team-gh
48 changes: 38 additions & 10 deletions controllers/tenant_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,15 +354,23 @@ func (r *TenantReconciler) patchRoleBinding(ctx context.Context, rb *acrbacv1.Ro
})
}

func rolesMap(delegates []cattagev1beta1.DelegateSpec) map[string][]string {
result := make(map[string][]string)
func (r *TenantReconciler) rolesMap(ctx context.Context, delegates []cattagev1beta1.DelegateSpec) (map[string][]Role, error) {
result := make(map[string][]Role)

for _, d := range delegates {
for _, role := range d.Roles {
result[role] = append(result[role], d.Name)
delegatedTenant := &cattagev1beta1.Tenant{}
err := r.client.Get(ctx, client.ObjectKey{Name: d.Name}, delegatedTenant)
if err != nil {
return nil, err
}
result[role] = append(result[role], Role{
Name: delegatedTenant.Name,
ExtraParams: delegatedTenant.Spec.ExtraParams,
})
}
}
return result
return result, nil
}

func (r *TenantReconciler) reconcileNamespaces(ctx context.Context, tenant *cattagev1beta1.Tenant) error {
Expand Down Expand Up @@ -395,13 +403,20 @@ func (r *TenantReconciler) reconcileNamespaces(ctx context.Context, tenant *catt
if err != nil {
return err
}
roles, err := r.rolesMap(ctx, tenant.Spec.Delegates)
if err != nil {
return err
}

var buf bytes.Buffer
err = tpl.Execute(&buf, struct {
Name string
Roles map[string][]string
Name string
Roles map[string][]Role
ExtraParams map[string]string
}{
Name: tenant.Name,
Roles: rolesMap(tenant.Spec.Delegates),
Name: tenant.Name,
Roles: roles,
ExtraParams: tenant.Spec.ExtraParams,
})
if err != nil {
return err
Expand Down Expand Up @@ -445,6 +460,11 @@ func (r *TenantReconciler) reconcileNamespaces(ctx context.Context, tenant *catt
return nil
}

type Role struct {
Name string
ExtraParams map[string]string
}

func (r *TenantReconciler) reconcileArgoCD(ctx context.Context, tenant *cattagev1beta1.Tenant) error {
logger := log.FromContext(ctx)

Expand All @@ -469,17 +489,24 @@ func (r *TenantReconciler) reconcileArgoCD(ctx context.Context, tenant *cattagev
return err
}

roles, err := r.rolesMap(ctx, tenant.Spec.Delegates)
if err != nil {
return err
}

var buf bytes.Buffer
err = tpl.Execute(&buf, struct {
Name string
Namespaces []string
Roles map[string][]string
Roles map[string][]Role
Repositories []string
ExtraParams map[string]string
}{
Name: tenant.Name,
Namespaces: namespaces,
Roles: rolesMap(tenant.Spec.Delegates),
Roles: roles,
Repositories: tenant.Spec.ArgoCD.Repositories,
ExtraParams: tenant.Spec.ExtraParams,
})
if err != nil {
return err
Expand All @@ -489,6 +516,7 @@ func (r *TenantReconciler) reconcileArgoCD(ctx context.Context, tenant *cattagev
dec := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme)
_, _, err = dec.Decode(buf.Bytes(), nil, proj)
if err != nil {
logger.Error(err, "failed to decode", "yaml", buf.String())
return err
}

Expand Down
39 changes: 32 additions & 7 deletions controllers/tenant_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,29 @@ var _ = Describe("Tenant controller", Ordered, func() {
})

It("should create root namespaces, rolebindings and an appproject", func() {
tenant := &cattagev1beta1.Tenant{
cTeam := &cattagev1beta1.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "c-team",
},
Spec: cattagev1beta1.TenantSpec{
RootNamespaces: []cattagev1beta1.RootNamespaceSpec{
{
Name: "app-c",
},
},
ArgoCD: cattagev1beta1.ArgoCDSpec{
Repositories: []string{
"https://github.com/cybozu-go/*",
},
},
ExtraParams: map[string]string{
"GitHubTeam": "c-team-gh",
},
},
}
err := k8sClient.Create(ctx, cTeam)
Expect(err).ToNot(HaveOccurred())
xTeam := &cattagev1beta1.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "x-team",
},
Expand Down Expand Up @@ -119,9 +141,12 @@ var _ = Describe("Tenant controller", Ordered, func() {
},
},
},
ExtraParams: map[string]string{
"GitHubTeam": "x-team-gh",
},
},
}
err := k8sClient.Create(ctx, tenant)
err = k8sClient.Create(ctx, xTeam)
Expect(err).ToNot(HaveOccurred())

ns := &corev1.Namespace{}
Expand Down Expand Up @@ -198,7 +223,7 @@ var _ = Describe("Tenant controller", Ordered, func() {
}),
"roles": ConsistOf(
MatchAllKeys(Keys{
"groups": ConsistOf("cybozu-go:x-team", "cybozu-go:c-team"),
"groups": ConsistOf("cybozu-go:x-team-gh", "cybozu-go:c-team-gh"),
"name": Equal("admin"),
"policies": ConsistOf("p, proj:x-team:admin, applications, *, x-team/*, allow"),
}),
Expand All @@ -214,14 +239,14 @@ var _ = Describe("Tenant controller", Ordered, func() {
err := k8sClient.Get(ctx, client.ObjectKey{Namespace: "argocd", Name: "all-tenant-namespaces-cm"}, allNsCm)
g.Expect(err).NotTo(HaveOccurred())
allNs := strings.Split(allNsCm.Data["application.namespaces"], ",")
g.Expect(allNs).Should(ConsistOf("app-x", "sub-4"))
g.Expect(allNs).Should(ConsistOf("app-x", "sub-4", "app-c"))
}).Should(Succeed())

Eventually(func(g Gomega) {
err := k8sClient.Get(ctx, client.ObjectKey{Namespace: "argocd", Name: "default-application-controller-cm"}, defaultCm)
g.Expect(err).NotTo(HaveOccurred())
defaultNs := strings.Split(defaultCm.Data["application.namespaces"], ",")
g.Expect(defaultNs).Should(ConsistOf("app-x", "sub-4"))
g.Expect(defaultNs).Should(ConsistOf("app-x", "sub-4", "app-c"))
}).Should(Succeed())

tenantS := &cattagev1beta1.Tenant{
Expand All @@ -245,13 +270,13 @@ var _ = Describe("Tenant controller", Ordered, func() {
err := k8sClient.Get(ctx, client.ObjectKey{Namespace: "argocd", Name: "all-tenant-namespaces-cm"}, allNsCm)
g.Expect(err).NotTo(HaveOccurred())
allNs := strings.Split(allNsCm.Data["application.namespaces"], ",")
g.Expect(allNs).Should(ConsistOf("app-x", "sub-4", "app-a", "sub-1", "sub-2", "sub-3"))
g.Expect(allNs).Should(ConsistOf("app-x", "sub-4", "app-a", "sub-1", "sub-2", "sub-3", "app-c"))
}).Should(Succeed())
Eventually(func(g Gomega) {
err := k8sClient.Get(ctx, client.ObjectKey{Namespace: "argocd", Name: "default-application-controller-cm"}, defaultCm)
g.Expect(err).NotTo(HaveOccurred())
defaultNs := strings.Split(defaultCm.Data["application.namespaces"], ",")
g.Expect(defaultNs).Should(ConsistOf("app-x", "sub-4"))
g.Expect(defaultNs).Should(ConsistOf("app-x", "sub-4", "app-c"))
}).Should(Succeed())
Eventually(func(g Gomega) {
err := k8sClient.Get(ctx, client.ObjectKey{Namespace: "argocd", Name: "second-application-controller-cm"}, secondCm)
Expand Down
4 changes: 2 additions & 2 deletions controllers/testdata/appprojecttemplate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ spec:
warn: false
roles:
- groups:
- cybozu-go:{{ .Name }}
- cybozu-go:{{with .ExtraParams.GitHubTeam}}{{ . }}{{else}}{{ .Name }}{{end}}
{{- range .Roles.admin }}
- cybozu-go:{{ . }}
- cybozu-go:{{with .ExtraParams.GitHubTeam}}{{ . }}{{else}}{{ .Name }}{{end}}
{{- end }}
name: admin
policies:
Expand Down
2 changes: 1 addition & 1 deletion controllers/testdata/rolebindingtemplate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ subjects:
{{- range .Roles.admin }}
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: {{ . }}
name: {{ .Name }}
{{- end }}
34 changes: 21 additions & 13 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ namespace:
{{- range .Roles.admin }}
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: {{ . }}
name: {{ .Name }}
{{- end }}
argocd:
namespace: argocd
Expand All @@ -53,9 +53,10 @@ argocd:
{{- end }}
roles:
- groups:
- {{ .Name }}
# If `GitHubName` is specified as `ExtraParams`, use it, otherwise use `Name`.
- {{with .ExtraParams.GitHubTeam}}{{ . }}{{else}}{{ .Name }}{{end}}
{{- range .Roles.admin }}
- {{ . }}
- {{with .ExtraParams.GitHubTeam}}{{ . }}{{else}}{{ .Name }}{{end}}
{{- end }}
name: admin
policies:
Expand All @@ -76,19 +77,26 @@ argocd:

`roleBindingTemplate` can use the following variables:

| Key | Type | Description |
|---------|-----------------------|----------------------------------------------------------------------------------|
| `Name` | `string` | The name of the tenant. |
| `Roles` | `map[string][]string` | Map of other tenants that are accessible to this tenant. The key is a role name. |
| Key | Type | Description |
|---------------|---------------------|----------------------------------------------------------------------------------|
| `Name` | `string` | The name of the tenant. |
| `Roles` | `map[string]Role` | Map of other tenants that are accessible to this tenant. The key is a role name. |
| `ExtraParams` | `map[string]string` | Extra parameters specified per tenant. |

`appProjectTemplate` can use the following variables:

| Key | Type | Description |
|----------------|-----------------------|----------------------------------------------------------------------------------|
| `Name` | `string` | The name of the tenant. |
| `Namespaces` | `[]string` | List of namespaces belonging to a tenant (including sub-namespaces). |
| `Repositories` | `[]string` | List of repository URLs which can be used by the tenant. |
| `Roles` | `map[string][]string` | Map of other tenants that are accessible to this tenant. The key is a role name. |
| Key | Type | Description |
|----------------|---------------------|----------------------------------------------------------------------------------|
| `Name` | `string` | The name of the tenant. |
| `Namespaces` | `[]string` | List of namespaces belonging to a tenant (including sub-namespaces). |
| `Repositories` | `[]string` | List of repository URLs which can be used by the tenant. |
| `Roles` | `map[string]Role` | Map of other tenants that are accessible to this tenant. The key is a role name. |
| `ExtraParams` | `map[string]string` | Extra parameters specified per tenant. |

| Key | Type | Description |
|---------------|---------------------|----------------------------------------|
| `Name` | `string` | The name of the tenant. |
| `ExtraParams` | `map[string]string` | Extra parameters specified per tenant. |

## Environment variables

Expand Down
1 change: 1 addition & 0 deletions docs/crd_tenant.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ TenantSpec defines the desired state of Tenant.
| argocd | ArgoCD is the settings of Argo CD for this tenant. | [ArgoCDSpec](#argocdspec) | false |
| delegates | Delegates is a list of other tenants that are delegated access to this tenant. | [][DelegateSpec](#delegatespec) | false |
| controllerName | ControllerName is the name of the application-controller that manages this tenant's applications. If not specified, the default controller is used. | string | false |
| extraParams | ExtraParams is a map of extra parameters that can be used in the templates. | map[string]string | false |

[Back to Custom Resources](#custom-resources)

Expand Down
4 changes: 2 additions & 2 deletions docs/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ controller:
{{- range .Roles.admin }}
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: {{ . }}
name: {{ .Name }}
{{- end }}
argocd:
namespace: argocd
Expand All @@ -128,7 +128,7 @@ controller:
- groups:
- {{ .Name }}
{{- range .Roles.admin }}
- {{ . }}
- {{ .Name }}
{{- end }}
name: admin
policies:
Expand Down
Loading