Skip to content

Commit

Permalink
feat: Refactor set-namespace (#785)
Browse files Browse the repository at this point in the history
Co-authored-by: Sunil Arora <[email protected]>
  • Loading branch information
yuwenma and droot authored Apr 6, 2022
1 parent e649e50 commit 366d9be
Show file tree
Hide file tree
Showing 10 changed files with 470 additions and 204 deletions.
2 changes: 1 addition & 1 deletion examples/set-namespace-imperative/.expected/config.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
testType: eval
image: gcr.io/kpt-fn/set-namespace:unstable
args:
namespace: example-ns
namespace: new-ns
10 changes: 5 additions & 5 deletions examples/set-namespace-imperative/.expected/diff.patch
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
diff --git a/app.yaml b/app.yaml
index 1f8aeee..33e42da 100644
index d67a0d2..bf55161 100644
--- a/app.yaml
+++ b/app.yaml
@@ -9,7 +9,7 @@ apiVersion: v1
kind: Service
metadata:
name: the-service
- namespace: the-namespace
+ namespace: example-ns
- namespace: example
+ namespace: new-ns
spec:
ports:
- name: etcd-server-ssl
@@ -21,4 +21,4 @@ spec:
@@ -34,4 +34,4 @@ spec:
apiVersion: v1
kind: Namespace
metadata:
- name: example
+ name: example-ns
+ name: new-ns
9 changes: 5 additions & 4 deletions examples/set-namespace-imperative/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

### Overview

This examples shows how to set namespace in the `.metadata.namespace` field on
all resources by running [`set-namespace`] function imperatively. Resources that
are known to be cluster-scoped will be skipped.
This examples shows how to replace KRM resources' namespace fields by matching
the namespace with the namespace object's `metadata.name`.
The example uses `kpt fn eval` to run the function imperatively.

### Fetch the example package

Expand All @@ -27,6 +27,7 @@ The desired namespace is provided after `--` and it will be converted to

### Expected result

Check all resources have `metadata.namespace` set to `example-ns`:
Only the namespace fields which match the `namespace` "example" object has the value updated to
`new-ns`:

[`set-namespace`]: https://catalog.kpt.dev/set-namespace/v0.1/
15 changes: 14 additions & 1 deletion examples/set-namespace-imperative/app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,20 @@ apiVersion: v1
kind: Service
metadata:
name: the-service
namespace: the-namespace
namespace: example
spec:
ports:
- name: etcd-server-ssl
port: 2380
- name: etcd-client-ssl
port: 2379
publishNotReadyAddresses: true
---
apiVersion: v1
kind: Service
metadata:
name: the-service
namespace: not-match-example
spec:
ports:
- name: etcd-server-ssl
Expand Down
136 changes: 91 additions & 45 deletions functions/go/set-namespace/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,68 +17,114 @@ Namespaces are often used in the following scenarios:

## Usage

This function can be used with any KRM function orchestrators (e.g. kpt).

- If the resource is `Namespace`, `set-namespace` updates the `metadata.name` field.
- If the resource is `RoleBinding` or `ClusterRoleBinding` resource, the function updates
the namespace field in the `subjects` element whose name is `default`.
- If the resource is `CustomResourceDefinition` (CRD), `set-namespace` updates the
`spec/conversion/webhook/clientConfig/service/namespace` field.
- If the resource is `APIService`, `set-namespace` updates the
`spec/service/namespace` field.
- If there is a [`depends-on`] annotation for a namespaced resource, the namespace
section of the annotation will be updated if the referenced resource is also
declared in the package.
This function replaces the KRM resources existing namespace to a new value.

### Target KRM resources

- This function updates all namespace-scoped KRM resources `metadata.namespace` fields.
We determine whether a KRM resource is namespace scoped by checking if it has `metadata.namespace` set and matches the "oldNamespace"
If not, this function won't add new namespace.
- This function updates `RoleBinding` and `ClusterRoleBinding` resources `subjects` element whose kind is `ServiceAccount`
and the subject's `namespace` is set and matches the "oldNamespace".
- This function updates `CustomResourceDefinition` (CRD) `spec/conversion/webhook/clientConfig/service/namespace` field
if the field is set and matches the "oldNamespace"
- This function updates `APIService` `spec/service/namespace` field if the field is set and matches the "oldNamespace"
- This function updates the KRM resources annotation `config.kubernetes.io/depends-on` if this annotation contains the
matching namespace.

### FunctionConfig

This function supports the default `ConfigMap` as function config and a custom `SetNamespace`. See below examples

`ConfigMap` as functionConfig
```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: sa
namespace: example
annotations:
config.kubernetes.io/depends-on: /namespaces/example/ServiceAccount/foo # <= this will NOT be updated (resource not declared)
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
...
annotations:
config.kubernetes.io/depends-on: /namespaces/example/ServiceAccount/sa # <== this will be updated (resource declared)
subjects:
- kind: ServiceAccount
name: default # <================== name default is used
namespace: example # <================== this will be updated
roleRef:
kind: Role
name: confluent-operator
apiGroup: rbac.authorization.k8s.io
kind: ConfigMap
data:
namespace: newNamespace # required
namespaceMatcher: example # update namespace whose value is "example" to "newNamespace"
```
This function can be used both declaratively and imperatively.
`SetNamespace` as functionConfig
```yaml
apiVersion: fn.kpt.dev/v1alpha1
kind: SetNamespace
namespace: newNamespace # required
namespaceMatcher: example # update namespace whose value is "example" to "newNamespace"
```

### FunctionConfig

There are 2 kinds of `functionConfig` supported by this function:
### Three updating modes

- `ConfigMap`
- A custom resource of kind `SetNamespace`
This function supports three modes to flexibly choose and update the target namespaces.

To use a `ConfigMap` as the `functionConfig`, the desired namespace must be
specified in the `data.namespace` field.
##### Restrict Mode
All target KRM resources namespace has to have the same value. All namespace will be updated to the new value.

To add a namespace `staging` to all resources, we use the
following `functionConfig`:
`ConfigMap` as functionConfig
```yaml
apiVersion: v1
kind: ConfigMap
data:
namespace: newNamespace # update all namespace fields to "newNamespace"
```

##### DefaultNamespace Mode

The input `resourcelist.items` contains one and only one `Namespace` object. The function matches the namespace `metadata.name`
with all other KRM resources, and only update the namespace if it matches the `Namespace` object.
If more than one `Namespace` objects are found, raise errors;

```yaml
kind: ResourceList
functionConfig:
apiVersion: v1
kind: ConfigMap
data:
namespace: newNs
items:
- apiVersion: v1
kind: Namespace
metadata:
name: example # updated to "newNs"
- apiVersion: v1
kind: Service
metadata:
name: the-service1
namespace: example # updated to "newNs"
- apiVersion: v1
kind: Service
metadata:
name: the-service2
namespace: irrelevant # skip since namespace does not match "example".
```

##### Matcher Mode

Only updates the namespace which matches a given value. The "oldNamespace" refers to the argument in FunctionConfig

`ConfigMap` as functionConfig
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-config
data:
namespace: staging
namespace: newNamespace
namespaceMatcher: example # update namespace whose value is "example" to "newNamespace"
```

`SetNamespace` as functionConfig
```yaml
apiVersion: fn.kpt.dev/v1alpha1
kind: SetNamespace
namespace: newNamespace
namespaceMatcher: example # update namespace whose value is "example" to "newNamespace"
```

### DependsOn annotation

DependsOn annotation is a [kpt feature](https://kpt.dev/reference/annotations/depends-on/). This function updates the
namespace segment in a depends-on annotation if the namespace matches the `Namespace` object or `namespaceMatcher` field.

<!--mdtogo-->

[namespace]: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
Expand Down
130 changes: 83 additions & 47 deletions functions/go/set-namespace/generated/docs.go

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

Loading

0 comments on commit 366d9be

Please sign in to comment.