9. Namespace Management¶
This section provides an overview of user management of Kubernetes namespaces by Robin CNS.
Topics covered in this chapter:
|
Namespace list |
|
Add a namespace for a user/tenant |
|
Remove a namespace |
|
Show information for a namespace |
|
Share a namespace with one or more users |
|
Stop sharing a namespace with one or more users |
|
List namespace shares showing which users have been extended access to specific namespaces for particular operations. |
|
Change the owner of a namespace. By default, ownership of any apps deployed by the original owner to the namespace will also transfer to the new owner. |
9.1. Kubernetes Namespaces¶
The Kubernetes ‘namespace’ construct allows a cluster to be partitioned into multiple “virtual clusters”. Names of resources deployed (scoped) to a namespace must be unique. This restriction does not, however, apply to resources deployed to multiple namespaces.
In addition to isolating application resources, namespaces provide a means of isolating users and groups of users. A user can be granted permission to access specific resources bound to a namespace. Or, they can be granted cluster-wide permissions to access resources in all namespaces as well as resources that are cluster scoped.
Kubernetes provides two objects for describing rules that define a set of permissions (actions that can be performed on specific resources). A Role object defines actions that can be performed on resources that are bound to a specific namespace. A ClusterRole object also can define actions that can be performed on namespace scoped resources. In addition, it can define actions that can be performed on cluster scoped resources (global resources that are not bound to a namespace).
Kubernetes also provides objects that bind Role and ClusterRole objects to users, groups of users, or services, granting them the permissions described. A RoleBinding object binds a Role or ClusterRole object to specific users for a specific namespace. A ClusterRoleBinding object performs the same function, however it grants the permissions cluster-wide.
Rules that are defined in Role and ClusterRole objects are additive, meaning that they only extend permissions, they never deny permissions. In addition, multiple Role and ClusterRole objects can be bound to a user or group of users. This provides flexibility when managing control of a Kubernetes cluster and the objects deployed to it.
9.2. Robin Managed Namespaces¶
Each Robin user is assigned a primary Kubernetes namespace for each tenant they are a member of. By default, all apps deployed by a user when logged into a tenant are scoped to their primary namespace for that tenant. By convention, a user’s primary namespace takes the following form:
t<tenant_id>-u<user_id>
with each id being zero padded to the left. For example, the primary namespace for a user with ID ‘9’ who is a member of tenant with ID ‘4’ is
t004-u000009
Note that when adding a user to a tenant, it’s possible to specify a custom namespace name for use as the user’s primary namespace. As was stated above, once the namespace has been created, it can’t be changed (e.g., renamed or replaced) and can only be reassigned when the user is removed from the tenant.
In addition to their primary namespace, each Robin user can create additional, custom namespaces (assuming they have adequate permission to do so), which are bound to the tenant the user was logged into when the namespace was created. If the namespace already exists in the underlying Kubernetes cluster, it will imported and become one of the user’s managed namespaces. If the namespace does not exit, it will be created before adding it to the Robin cluster. Note that once created, a namespace’s name cannot be changed, nor can its tenant affiliation be changed.
A user’s ability to manage namespaces (create, delete, or modify) is controlled by the ManageNamespaces user capability. This capability is enabled by default for all users, but can be disabled for individual users.
A Robin user can always remove a namespace they created (assuming there are no applications deployed to the namespace and the namespace has not been shared with any other users). By default, when a namespace is removed from Robin, the underlying Kubernetes namespace will also be removed (deleted), along with any objects that were deployed to the namespace. If this behavior is not desired, there is an option to remove the namespace from the Robin cluster, but leave it intact in the Kubernetes cluster.
9.2.1. Namespace Sharing¶
A namespace can be shared with one or more members of the tenant it is bound to. Or, it can be shared with all tenant members. When the namespace is shared with all tenant users, it will automatically be shared with any users that get added to the tenant. Note that only users with ‘superadmin’ or ‘tenatadmin’ permissions can share a namespace with other tenant members (a user with ‘tenantadmin’ permissions can only share namespaces when they are logged into the tenant the namespace is bound to).
Users that have access to a namespace (because they created it or it was shared with them) will be able to deploy applications to that namespace (subject to RBAC control/limitations). Once an app is deployed, it can be shared with other tenant members. Note that sharing an app with other tenant members requires that they be able to access the namespace the app is deployed to. Also note that just like namespace share, app sharing can only be performed by a ‘superadmin’ or ‘tenantadmin’ user.
As a general rule, apps that need to be accessed by multiple users in a tenant should not be scoped to a user’s primary namespace, as doing so allows access to ALL apps deployed by the user to their namespace. Instead, shared apps should be scoped to a custom namespace that is bound to the tenant. Note that custom namespaces are still owned by a member of the tenant (the user who created it, or the user who was assigned ownership when the namespace was created).
9.2.2. Namespace Ownership Reassignment¶
In addition to sharing access to a namespace, it’s also possible to reassign ownership of a namespace to another member of the tenant the namespace is bound to. This may be necessary when removing a user from a tenant. If, when removing the user, there aren’t any apps deployed to the namespace, then it’s safe to remove the namespace. On the other hand, if there are apps deployed to the namespaces, then the apps must be deleted or their ownership assigned to another member of the tenant. In addition to reassigning ownership of the apps, ownership of any namespace the apps are deployed to also needs to be reassigned. This can be done manually, or as part of the operation to remove the user.
Ownership of a user’s primary namespace can only be reassigned when the user is removed from a tenant. Ownership of any apps the user deployed to that namespace can be reassigned, however, provided the new owner has access to the namespace the app is scoped to (they are a ‘tenantadmin’ or the namespace was shared with them). Note that only users with ‘superadmin’ and ‘tenantadmin’ capabilities can reassign ownership of a namespace (or any other managed object) in a Robin cluster.
When removing a user from a tenant, the operation will fail if the user has deployed any apps, uploaded any bundles, etc. Before the user can be removed from a tenant, all objects they own, that they created when logged into that tenant, must be removed/deleted, or have their ownership reassigned. This can be done as a prerequisite to removing the user. Or, it can be taken care of during the user removal process itself.
9.2.3. Default Namespace in a User Context¶
Each logged in Robin user has a user context that identifies which tenant they are logged into, which namespace to use as the default namespace, authorization credentials for accessing the Kubernetes API server for that namespace, etc. Any apps deployed by the user when logged into the tenant will be deployed into their default namespace. By default, a user’s primary namespace for their current tenant will be their default namespace. This can be overridden by the user when creating the app, by specifying the namespace.
When logging into a Robin cluster, a user can specify which namespace they want as their default for their current tenant. A user also can change their default namespace at any time during their login session. Note that the user is only allowed to specify a namespace they own (they created it or its ownership was assigned to them when it was created), or has been given access to via sharing.
9.3. Namespace Operations¶
9.3.1. List Namespaces¶
List information about the Kubernetes namespaces managed by the Robin cluster.
robin namespace list [name]
--username <username>
--tenant <tenant>
--primary-namespace
--all
|
Namespace name |
|
Filter by user |
|
Filter by tenant |
|
Filter by primary namespace |
|
List namespaces for all users including hidden and disabled users |
Example:
# robin namespace list
Name | Owner/Tenant | Primary Namespace | Imported | Snapshots | Backups
-------------+----------------------+-------------------+----------+-----------+---------
t001-u000003 | admin/Administrators | True | False | 0 | 0
ns1 | admin/Administrators | False | False | 1 | 0
ns2 | admin/Administrators | False | False | 0 | 0
ns3 | admin/Administrators | False | False | 0 | 0
ns4 | admin/Administrators | False | False | 0 | 0
ns5 | admin/Administrators | False | False | 0 | 0
ns6 | admin/Administrators | False | False | 0 | 0
t002-u000004 | u1/t1 | True | False | 0 | 0
t003-u000005 | u2/t2 | True | False | 0 | 0
t004-u000006 | u3/t3 | True | False | 0 | 0
Note
The list of namespaces returned by the robin namespace list
command depends on the role of the user issuing the command.
Regular users (users with the user role) will only be able to
see namespaces they own or that have been shared with them. Tenant
Administrators (users with the tenantadmin role) will see all
namespaces bound to their tenant, and Cluster Administrators
(users with the superadmin role) will see all namespaces.
List information about the Kubernetes namespaces managed by the Robin cluster.
End Point: /api/v3/robin_server/namespaces
Method: GET
URL Parameters: None
Data Parameters:
username: <username>
- Utilizing this parameter within the payload, by specifying the name of a user, results in the list of namespaces being filtered by the aforementioned user.tenant: <tenant>
- Utilizing this parameter within the payload, by specifying the name of a tenant, results in the list of namespaces being filtered by the aforementioned tenant.primary_namespace: true
- Utilizing this parameter within the payload results in the list of namespaces being filtered such that only namespaces which are primary namespaces for users are returned.all_users: true
- Utilizing this parameter within the payload results in the namespaces for all users, including hidden and disabled users, being returned.
Port: RCM Port (default value is 29442)
Headers:
Authorization: <auth_token>
: Authorization token to identify which user is sending the request. The token can be acquired from the login API.
Success Response Code: 200
Error Response Code: 500 (Internal Server Error), 401 (Unauthorized Error), 400 (Invalid API Usage Error)
Example Response:
Output
{
"object_type":"NamespaceRecord",
"start":1,
"count":20,
"total":24,
"page_size":20,
"page_num":1,
"items":[
{
"id":3,
"name":"t001-u000003",
"user_id":3,
"tenant_id":1,
"primary_namespace":true,
"username":"admin",
"tenant":"Administrators",
"imported":false,
"snapshots":[
],
"backups":[
]
},
{
"id":4,
"name":"ns1",
"user_id":3,
"tenant_id":1,
"primary_namespace":false,
"username":"admin",
"tenant":"Administrators",
"imported":false,
"snapshots":[
{
"snap_name":"ns1obcrh_nss1",
"spec":"apiVersion: v1\ndata: {run.sh: ''}\nkind: ConfigMap\nmetadata:\n annotations: {meta.helm.sh\/release-name: mysql1, meta.helm.sh\/release-namespace: ns1}\n labels: {app: mysql1, app.kubernetes.io\/managed-by: Helm, chart: mysql-1.6.7, heritage: Helm,\n release: mysql1}\n name: mysql1-test\n namespace: ns1\n---\napiVersion: v1\ndata: {mysql-password: WkFLQ2tnZnJETA==, mysql-root-password: MTh4WUpMVFNPag==}\nkind: Secret\nmetadata:\n annotations: {meta.helm.sh\/release-name: mysql1, meta.helm.sh\/release-namespace: ns1}\n labels: {app: mysql1, app.kubernetes.io\/managed-by: Helm, chart: mysql-1.6.7, heritage: Helm,\n release: mysql1}\n name: mysql1\n namespace: ns1\ntype: Opaque\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n annotations: {meta.helm.sh\/release-name: mysql1, meta.helm.sh\/release-namespace: ns1,\n robin.io\/appid: '1', robin.io\/blocksize: '4096', robin.io\/encryption: none, robin.io\/fstype: ext4,\n robin.io\/snapname: ns1obcrh_nss1, robin.io\/snapshotid: '4', robin.io\/vol_snapname: nss1,\n robin.io\/volumeid: '9', robin.io\/volumename: pvc-574b9417-0dd9-4eef-8d9b-9269d95be0ce,\n robin.io\/zoneid: '1630920119', volume.beta.kubernetes.io\/storage-provisioner: robin}\n labels: {app: mysql1, app.kubernetes.io\/managed-by: Helm, chart: mysql-1.6.7, heritage: Helm,\n release: mysql1}\n name: mysql1\n namespace: ns1\nspec:\n accessModes: [ReadWriteOnce]\n resources:\n requests: {storage: 1Gi}\n storageClassName: robin\n volumeMode: Filesystem\n---\napiVersion: v1\nkind: Service\nmetadata:\n annotations: {meta.helm.sh\/release-name: mysql1, meta.helm.sh\/release-namespace: ns1}\n labels: {app: mysql1, app.kubernetes.io\/managed-by: Helm, chart: mysql-1.6.7, heritage: Helm,\n release: mysql1}\n name: mysql1\n namespace: ns1\nspec:\n ipFamilies: [IPv4]\n ipFamilyPolicy: SingleStack\n ports:\n - {name: mysql, port: 3306, protocol: TCP, targetPort: mysql}\n selector: {app: mysql1}\n sessionAffinity: None\n type: ClusterIP\n---\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n annotations: {deployment.kubernetes.io\/revision: '1', meta.helm.sh\/release-name: mysql1,\n meta.helm.sh\/release-namespace: ns1}\n labels: {app: mysql1, app.kubernetes.io\/managed-by: Helm, chart: mysql-1.6.7, heritage: Helm,\n release: mysql1}\n name: mysql1\n namespace: ns1\nspec:\n progressDeadlineSeconds: 600\n replicas: 1\n revisionHistoryLimit: 10\n selector:\n matchLabels: {app: mysql1, release: mysql1}\n strategy: {type: Recreate}\n template:\n metadata:\n creationTimestamp: null\n labels: {app: mysql1, release: mysql1}\n spec:\n containers:\n - env:\n - name: MYSQL_ROOT_PASSWORD\n valueFrom:\n secretKeyRef: {key: mysql-root-password, name: mysql1}\n - name: MYSQL_PASSWORD\n valueFrom:\n secretKeyRef: {key: mysql-password, name: mysql1, optional: true}\n - {name: MYSQL_USER}\n - {name: MYSQL_DATABASE}\n image: mysql:5.7.30\n imagePullPolicy: IfNotPresent\n livenessProbe:\n exec:\n command: [sh, -c, 'mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}']\n failureThreshold: 3\n initialDelaySeconds: 30\n periodSeconds: 10\n successThreshold: 1\n timeoutSeconds: 5\n name: mysql1\n ports:\n - {containerPort: 3306, name: mysql, protocol: TCP}\n readinessProbe:\n exec:\n command: [sh, -c, 'mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}']\n failureThreshold: 3\n initialDelaySeconds: 5\n periodSeconds: 10\n successThreshold: 1\n timeoutSeconds: 1\n resources:\n requests: {cpu: 100m, memory: 256Mi}\n securityContext: {privileged: true, runAsUser: 0}\n terminationMessagePath: \/dev\/termination-log\n terminationMessagePolicy: File\n volumeMounts:\n - {mountPath: \/var\/lib\/mysql, name: data}\n dnsPolicy: ClusterFirst\n initContainers:\n - command: [rm, -fr, \/var\/lib\/mysql\/lost+found]\n image: busybox:1.32\n imagePullPolicy: IfNotPresent\n name: remove-lost-found\n resources:\n requests: {cpu: 10m, memory: 10Mi}\n terminationMessagePath: \/dev\/termination-log\n terminationMessagePolicy: File\n volumeMounts:\n - {mountPath: \/var\/lib\/mysql, name: data}\n restartPolicy: Always\n schedulerName: default-scheduler\n securityContext: {}\n serviceAccount: default\n serviceAccountName: default\n terminationGracePeriodSeconds: 30\n volumes:\n - name: data\n persistentVolumeClaim: {claimName: mysql1}\n"
}
],
"backups":[
]
},
{
"id":5,
"name":"ns2",
"user_id":3,
"tenant_id":1,
"primary_namespace":false,
"username":"admin",
"tenant":"Administrators",
"imported":false,
"snapshots":[
],
"backups":[
]
},
{
"id":6,
"name":"ns3",
"user_id":3,
"tenant_id":1,
"primary_namespace":false,
"username":"admin",
"tenant":"Administrators",
"imported":false,
"snapshots":[
],
"backups":[
]
},
{
"id":7,
"name":"ns4",
"user_id":3,
"tenant_id":1,
"primary_namespace":false,
"username":"admin",
"tenant":"Administrators",
"imported":false,
"snapshots":[
],
"backups":[
]
},
{
"id":8,
"name":"ns5",
"user_id":3,
"tenant_id":1,
"primary_namespace":false,
"username":"admin",
"tenant":"Administrators",
"imported":false,
"snapshots":[
],
"backups":[
]
},
{
"id":9,
"name":"ns6",
"user_id":3,
"tenant_id":1,
"primary_namespace":false,
"username":"admin",
"tenant":"Administrators",
"imported":false,
"snapshots":[
],
"backups":[
]
},
{
"id":10,
"name":"t002-u000004",
"user_id":4,
"tenant_id":2,
"primary_namespace":true,
"username":"u1",
"tenant":"t1",
"imported":false,
"snapshots":[
],
"backups":[
]
},
{
"id":11,
"name":"t003-u000005",
"user_id":5,
"tenant_id":3,
"primary_namespace":true,
"username":"u2",
"tenant":"t2",
"imported":false,
"snapshots":[
],
"backups":[
]
},
{
"id":12,
"name":"t004-u000006",
"user_id":6,
"tenant_id":4,
"primary_namespace":true,
"username":"u3",
"tenant":"t3",
"imported":false,
"snapshots":[
],
"backups":[
]
},
{
"id":13,
"name":"t002-u000007",
"user_id":7,
"tenant_id":2,
"primary_namespace":true,
"username":"u11",
"tenant":"t1",
"imported":false,
"snapshots":[
],
"backups":[
]
},
{
"id":14,
"name":"t003-u000008",
"user_id":8,
"tenant_id":3,
"primary_namespace":true,
"username":"u21",
"tenant":"t2",
"imported":false,
"snapshots":[
],
"backups":[
]
},
{
"id":15,
"name":"t004-u000009",
"user_id":9,
"tenant_id":4,
"primary_namespace":true,
"username":"u31",
"tenant":"t3",
"imported":false,
"snapshots":[
],
"backups":[
]
},
{
"id":16,
"name":"t002-u000010",
"user_id":10,
"tenant_id":2,
"primary_namespace":true,
"username":"u12",
"tenant":"t1",
"imported":false,
"snapshots":[
],
"backups":[
]
},
{
"id":17,
"name":"t003-u000011",
"user_id":11,
"tenant_id":3,
"primary_namespace":true,
"username":"u22",
"tenant":"t2",
"imported":false,
"snapshots":[
],
"backups":[
]
},
{
"id":18,
"name":"t004-u000012",
"user_id":12,
"tenant_id":4,
"primary_namespace":true,
"username":"u32",
"tenant":"t3",
"imported":false,
"snapshots":[
],
"backups":[
]
},
{
"id":19,
"name":"u1ns1",
"user_id":4,
"tenant_id":2,
"primary_namespace":false,
"username":"u1",
"tenant":"t1",
"imported":false,
"snapshots":[
{
"snap_name":"u1ns1iquap_ss1u1ns1",
"spec":"apiVersion: v1\ndata: {run.sh: ''}\nkind: ConfigMap\nmetadata:\n annotations: {meta.helm.sh\/release-name: mysql1t1u1ns1, meta.helm.sh\/release-namespace: u1ns1}\n labels: {app: mysql1t1u1ns1, app.kubernetes.io\/managed-by: Helm, chart: mysql-1.6.7,\n heritage: Helm, release: mysql1t1u1ns1}\n name: mysql1t1u1ns1-test\n namespace: u1ns1\n---\napiVersion: v1\ndata: {mysql-password: S3FLNk1ZQUVyTA==, mysql-root-password: d1NQS3NDaUhHWA==}\nkind: Secret\nmetadata:\n annotations: {meta.helm.sh\/release-name: mysql1t1u1ns1, meta.helm.sh\/release-namespace: u1ns1}\n labels: {app: mysql1t1u1ns1, app.kubernetes.io\/managed-by: Helm, chart: mysql-1.6.7,\n heritage: Helm, release: mysql1t1u1ns1}\n name: mysql1t1u1ns1\n namespace: u1ns1\ntype: Opaque\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n annotations: {meta.helm.sh\/release-name: mysql1t1u1ns1, meta.helm.sh\/release-namespace: u1ns1,\n robin.io\/appid: '1', robin.io\/blocksize: '4096', robin.io\/encryption: none, robin.io\/fstype: ext4,\n robin.io\/snapname: u1ns1iquap_ss1u1ns1, robin.io\/snapshotid: '1', robin.io\/vol_snapname: ss1u1ns1,\n robin.io\/volumeid: '17', robin.io\/volumename: pvc-1580fec7-ba32-4bf2-9e20-864754b5de43,\n robin.io\/zoneid: '1630920119', volume.beta.kubernetes.io\/storage-provisioner: robin}\n labels: {app: mysql1t1u1ns1, app.kubernetes.io\/managed-by: Helm, chart: mysql-1.6.7,\n heritage: Helm, release: mysql1t1u1ns1}\n name: mysql1t1u1ns1\n namespace: u1ns1\nspec:\n accessModes: [ReadWriteOnce]\n resources:\n requests: {storage: 1Gi}\n storageClassName: robin\n volumeMode: Filesystem\n---\napiVersion: v1\nkind: Service\nmetadata:\n annotations: {meta.helm.sh\/release-name: mysql1t1u1ns1, meta.helm.sh\/release-namespace: u1ns1}\n labels: {app: mysql1t1u1ns1, app.kubernetes.io\/managed-by: Helm, chart: mysql-1.6.7,\n heritage: Helm, release: mysql1t1u1ns1}\n name: mysql1t1u1ns1\n namespace: u1ns1\nspec:\n ipFamilies: [IPv4]\n ipFamilyPolicy: SingleStack\n ports:\n - {name: mysql, port: 3306, protocol: TCP, targetPort: mysql}\n selector: {app: mysql1t1u1ns1}\n sessionAffinity: None\n type: ClusterIP\n---\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n annotations: {deployment.kubernetes.io\/revision: '1', meta.helm.sh\/release-name: mysql1t1u1ns1,\n meta.helm.sh\/release-namespace: u1ns1}\n labels: {app: mysql1t1u1ns1, app.kubernetes.io\/managed-by: Helm, chart: mysql-1.6.7,\n heritage: Helm, release: mysql1t1u1ns1}\n name: mysql1t1u1ns1\n namespace: u1ns1\nspec:\n progressDeadlineSeconds: 600\n replicas: 1\n revisionHistoryLimit: 10\n selector:\n matchLabels: {app: mysql1t1u1ns1, release: mysql1t1u1ns1}\n strategy: {type: Recreate}\n template:\n metadata:\n creationTimestamp: null\n labels: {app: mysql1t1u1ns1, release: mysql1t1u1ns1}\n spec:\n containers:\n - env:\n - name: MYSQL_ROOT_PASSWORD\n valueFrom:\n secretKeyRef: {key: mysql-root-password, name: mysql1t1u1ns1}\n - name: MYSQL_PASSWORD\n valueFrom:\n secretKeyRef: {key: mysql-password, name: mysql1t1u1ns1, optional: true}\n - {name: MYSQL_USER}\n - {name: MYSQL_DATABASE}\n image: mysql:5.7.30\n imagePullPolicy: IfNotPresent\n livenessProbe:\n exec:\n command: [sh, -c, 'mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}']\n failureThreshold: 3\n initialDelaySeconds: 30\n periodSeconds: 10\n successThreshold: 1\n timeoutSeconds: 5\n name: mysql1t1u1ns1\n ports:\n - {containerPort: 3306, name: mysql, protocol: TCP}\n readinessProbe:\n exec:\n command: [sh, -c, 'mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}']\n failureThreshold: 3\n initialDelaySeconds: 5\n periodSeconds: 10\n successThreshold: 1\n timeoutSeconds: 1\n resources:\n requests: {cpu: 100m, memory: 256Mi}\n securityContext: {privileged: true, runAsUser: 0}\n terminationMessagePath: \/dev\/termination-log\n terminationMessagePolicy: File\n volumeMounts:\n - {mountPath: \/var\/lib\/mysql, name: data}\n dnsPolicy: ClusterFirst\n initContainers:\n - command: [rm, -fr, \/var\/lib\/mysql\/lost+found]\n image: busybox:1.32\n imagePullPolicy: IfNotPresent\n name: remove-lost-found\n resources:\n requests: {cpu: 10m, memory: 10Mi}\n terminationMessagePath: \/dev\/termination-log\n terminationMessagePolicy: File\n volumeMounts:\n - {mountPath: \/var\/lib\/mysql, name: data}\n restartPolicy: Always\n schedulerName: default-scheduler\n securityContext: {}\n serviceAccount: default\n serviceAccountName: default\n terminationGracePeriodSeconds: 30\n volumes:\n - name: data\n persistentVolumeClaim: {claimName: mysql1t1u1ns1}\n---\napiVersion: rbac.authorization.k8s.io\/v1\nkind: RoleBinding\nmetadata:\n labels: {robin.io\/domain: ROBIN, robin.io\/role: tenantadmin, robin.io\/tenant: t1,\n robin.io\/tenant_id: '2', robin.io\/user_id: '4', robin.io\/username: u1}\n name: rolebinding-u1-edit\n namespace: u1ns1\nroleRef: {apiGroup: rbac.authorization.k8s.io, kind: ClusterRole, name: edit}\nsubjects:\n- {apiGroup: rbac.authorization.k8s.io, kind: User, name: u1, namespace: u1ns1}\n"
}
],
"backups":[
{
"app_ref":16
}
]
},
{
"id":20,
"name":"u1ns1a1",
"user_id":4,
"tenant_id":2,
"primary_namespace":false,
"username":"u1",
"tenant":"t1",
"imported":false,
"snapshots":[
],
"backups":[
]
},
{
"id":21,
"name":"u11ns1",
"user_id":7,
"tenant_id":2,
"primary_namespace":false,
"username":"u11",
"tenant":"t1",
"imported":false,
"snapshots":[
{
"snap_name":"u11ns1plscf_ss1u11ns1",
"spec":"apiVersion: v1\ndata: {run.sh: ''}\nkind: ConfigMap\nmetadata:\n annotations: {meta.helm.sh\/release-name: mysql1t1u11ns1, meta.helm.sh\/release-namespace: u11ns1}\n labels: {app: mysql1t1u11ns1, app.kubernetes.io\/managed-by: Helm, chart: mysql-1.6.7,\n heritage: Helm, release: mysql1t1u11ns1}\n name: mysql1t1u11ns1-test\n namespace: u11ns1\n---\napiVersion: v1\ndata: {mysql-password: WVdvNFhrd1ZCOQ==, mysql-root-password: QVNRRVZhd3VQNQ==}\nkind: Secret\nmetadata:\n annotations: {meta.helm.sh\/release-name: mysql1t1u11ns1, meta.helm.sh\/release-namespace: u11ns1}\n labels: {app: mysql1t1u11ns1, app.kubernetes.io\/managed-by: Helm, chart: mysql-1.6.7,\n heritage: Helm, release: mysql1t1u11ns1}\n name: mysql1t1u11ns1\n namespace: u11ns1\ntype: Opaque\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n annotations: {meta.helm.sh\/release-name: mysql1t1u11ns1, meta.helm.sh\/release-namespace: u11ns1,\n robin.io\/appid: '1', robin.io\/blocksize: '4096', robin.io\/encryption: none, robin.io\/fstype: ext4,\n robin.io\/snapname: u11ns1plscf_ss1u11ns1, robin.io\/snapshotid: '1', robin.io\/vol_snapname: ss1u11ns1,\n robin.io\/volumeid: '19', robin.io\/volumename: pvc-f90e8ae4-56a4-4a7b-aaed-8c7ef337e4e8,\n robin.io\/zoneid: '1630920119', volume.beta.kubernetes.io\/storage-provisioner: robin}\n labels: {app: mysql1t1u11ns1, app.kubernetes.io\/managed-by: Helm, chart: mysql-1.6.7,\n heritage: Helm, release: mysql1t1u11ns1}\n name: mysql1t1u11ns1\n namespace: u11ns1\nspec:\n accessModes: [ReadWriteOnce]\n resources:\n requests: {storage: 1Gi}\n storageClassName: robin\n volumeMode: Filesystem\n---\napiVersion: v1\nkind: Service\nmetadata:\n annotations: {meta.helm.sh\/release-name: mysql1t1u11ns1, meta.helm.sh\/release-namespace: u11ns1}\n labels: {app: mysql1t1u11ns1, app.kubernetes.io\/managed-by: Helm, chart: mysql-1.6.7,\n heritage: Helm, release: mysql1t1u11ns1}\n name: mysql1t1u11ns1\n namespace: u11ns1\nspec:\n ipFamilies: [IPv4]\n ipFamilyPolicy: SingleStack\n ports:\n - {name: mysql, port: 3306, protocol: TCP, targetPort: mysql}\n selector: {app: mysql1t1u11ns1}\n sessionAffinity: None\n type: ClusterIP\n---\napiVersion: apps\/v1\nkind: Deployment\nmetadata:\n annotations: {deployment.kubernetes.io\/revision: '1', meta.helm.sh\/release-name: mysql1t1u11ns1,\n meta.helm.sh\/release-namespace: u11ns1}\n labels: {app: mysql1t1u11ns1, app.kubernetes.io\/managed-by: Helm, chart: mysql-1.6.7,\n heritage: Helm, release: mysql1t1u11ns1}\n name: mysql1t1u11ns1\n namespace: u11ns1\nspec:\n progressDeadlineSeconds: 600\n replicas: 1\n revisionHistoryLimit: 10\n selector:\n matchLabels: {app: mysql1t1u11ns1, release: mysql1t1u11ns1}\n strategy: {type: Recreate}\n template:\n metadata:\n creationTimestamp: null\n labels: {app: mysql1t1u11ns1, release: mysql1t1u11ns1}\n spec:\n containers:\n - env:\n - name: MYSQL_ROOT_PASSWORD\n valueFrom:\n secretKeyRef: {key: mysql-root-password, name: mysql1t1u11ns1}\n - name: MYSQL_PASSWORD\n valueFrom:\n secretKeyRef: {key: mysql-password, name: mysql1t1u11ns1, optional: true}\n - {name: MYSQL_USER}\n - {name: MYSQL_DATABASE}\n image: mysql:5.7.30\n imagePullPolicy: IfNotPresent\n livenessProbe:\n exec:\n command: [sh, -c, 'mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}']\n failureThreshold: 3\n initialDelaySeconds: 30\n periodSeconds: 10\n successThreshold: 1\n timeoutSeconds: 5\n name: mysql1t1u11ns1\n ports:\n - {containerPort: 3306, name: mysql, protocol: TCP}\n readinessProbe:\n exec:\n command: [sh, -c, 'mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}']\n failureThreshold: 3\n initialDelaySeconds: 5\n periodSeconds: 10\n successThreshold: 1\n timeoutSeconds: 1\n resources:\n requests: {cpu: 100m, memory: 256Mi}\n securityContext: {privileged: true, runAsUser: 0}\n terminationMessagePath: \/dev\/termination-log\n terminationMessagePolicy: File\n volumeMounts:\n - {mountPath: \/var\/lib\/mysql, name: data}\n dnsPolicy: ClusterFirst\n initContainers:\n - command: [rm, -fr, \/var\/lib\/mysql\/lost+found]\n image: busybox:1.32\n imagePullPolicy: IfNotPresent\n name: remove-lost-found\n resources:\n requests: {cpu: 10m, memory: 10Mi}\n terminationMessagePath: \/dev\/termination-log\n terminationMessagePolicy: File\n volumeMounts:\n - {mountPath: \/var\/lib\/mysql, name: data}\n restartPolicy: Always\n schedulerName: default-scheduler\n securityContext: {}\n serviceAccount: default\n serviceAccountName: default\n terminationGracePeriodSeconds: 30\n volumes:\n - name: data\n persistentVolumeClaim: {claimName: mysql1t1u11ns1}\n---\napiVersion: rbac.authorization.k8s.io\/v1\nkind: RoleBinding\nmetadata:\n labels: {app.kubernetes.io\/instance: robin, app.kubernetes.io\/managed-by: robin.io,\n app.kubernetes.io\/name: robin, robin.io\/domain: ROBIN, robin.io\/role: tenantadmin,\n robin.io\/tenant: t1, robin.io\/tenant_id: '2', robin.io\/user_id: '4', robin.io\/username: u1}\n name: rolebinding-u1-edit\n namespace: u11ns1\nroleRef: {apiGroup: rbac.authorization.k8s.io, kind: ClusterRole, name: edit}\nsubjects:\n- {apiGroup: rbac.authorization.k8s.io, kind: User, name: u1, namespace: u11ns1}\n---\napiVersion: rbac.authorization.k8s.io\/v1\nkind: RoleBinding\nmetadata:\n labels: {app.kubernetes.io\/instance: robin, app.kubernetes.io\/managed-by: robin.io,\n app.kubernetes.io\/name: robin, robin.io\/domain: ROBIN, robin.io\/role: user, robin.io\/tenant: t1,\n robin.io\/tenant_id: '2', robin.io\/user_id: '7', robin.io\/username: u11}\n name: rolebinding-u11-edit\n namespace: u11ns1\nroleRef: {apiGroup: rbac.authorization.k8s.io, kind: ClusterRole, name: edit}\nsubjects:\n- {apiGroup: rbac.authorization.k8s.io, kind: User, name: u11, namespace: u11ns1}\n"
}
],
"backups":[
{
"app_ref":17
}
]
},
{
"id":22,
"name":"u11ns1a1",
"user_id":7,
"tenant_id":2,
"primary_namespace":false,
"username":"u11",
"tenant":"t1",
"imported":false,
"snapshots":[
],
"backups":[
]
}
]
}
9.3.2. Show Information About a Specific Namespace¶
In order to attain details about a specific Kubernetes namespace managed by the Robin cluster such as the user and tenant its associated with, any snapshots of it that may exist and any repos it may be attached to, issue the following command:
robin namespace info <name>
|
Namespace name |
Example:
# robin namespace info u1ns1
Namespace: u1ns1
Primary Namespace: False
User: u1
Tenant: t1
Imported: False
Snapshots:
+----------------------------------+---------------------+----------------------+--------+
| ID | Name | Created | State |
+----------------------------------+---------------------+----------------------+--------+
| a44d6e3a108511ecb4620d978aa26f58 | u1ns1iquap_ss1u1ns1 | 08 Sep 2021 09:18:16 | ONLINE |
+----------------------------------+---------------------+----------------------+--------+
Backups:
+----------------------------------+---------------------------+----------------------+--------+
| ID | Name | Created | State |
+----------------------------------+---------------------------+----------------------+--------+
| a3b979f0108a11ec931c0d8a6d76a1ea | u1ns1_nsbackup-1631094817 | 08 Sep 2021 09:53:38 | Pushed |
+----------------------------------+---------------------------+----------------------+--------+
Repos:
+-------+-------------+--------+------------+
| Name | Bucket | Path | Permission |
+-------+-------------+--------+------------+
| repo1 | robin-pgsql | demo1/ | readwrite |
+-------+-------------+--------+------------+
Returns details about a specific namespace such as ther user and tenant associated with it, any snapshots of it that may exist and any repos it may be attached to it.
End Point: /api/v3/robin_server/namespaces/<namespace_name>
Method: GET
URL Parameters: None
Data Parameters: None
Port: RCM Port (default value is 29442)
Headers:
Authorization: <auth_token>
: Authorization token to identify which user is sending the request. The token can be acquired from the login API.
Success Response Code: 200
Error Response Code: 500 (Internal Server Error), 401 (Unauthorized Error), 400 (Invalid API Usage Error)
Example Response:
Output
{
"items":[
{
"id":19,
"name":"u1ns1",
"username":"u1",
"tenant":"t1",
"user_id":4,
"tenant_id":2,
"primary_namespace":false,
"imported":false,
"snapshots":[
{
"id":"a44d6e3a108511ecb4620d978aa26f58",
"name":"u1ns1iquap_ss1u1ns1",
"description":"Namespace u1ns1 snapshot",
"state":"ONLINE",
"create_time":1631092696,
"size":0
}
],
"enabled_snap_schedule_summary":{
},
"repos":[
{
"name":"repo1",
"params":"{\"repo_params\":\"<REDACTED>\",\"bucket\":\"robin-pgsql\",\"path\":\"demo1\\\/\",\"permissions\":\"readwrite\"}"
}
],
"backups":[
{
"id":"a3b979f0108a11ec931c0d8a6d76a1ea",
"name":"u1ns1_nsbackup-1631094817",
"description":"-",
"state":"Pushed",
"create_time":1631094818,
"size":369098752
}
],
"enabled_backup_schedule_summary":{
},
"snapback":{
"snapshot":{
},
"backup":{
}
}
}
],
"network_policies":{
"u1ns1":[
]
}
}
Returns details about a specific namespace such as ther user and tenant associated with it, any snapshots of it that may exist and any repos it may be attached to it.
End Point: /api/v3/robin_server/namespaces/<namespace_name>
Method: GET
URL Parameters: None
Data Parameters: None
Port: RCM Port (default value is 29442)
Headers:
Authorization: <auth_token>
: Authorization token to identify which user is sending the request. The token can be acquired from the login API.
Success Response Code: 200
Error Response Code: 500 (Internal Server Error), 401 (Unauthorized Error), 400 (Invalid API Usage Error)
Example Response:
Output
{
"items":[
{
"id":19,
"name":"u1ns1",
"username":"u1",
"tenant":"t1",
"user_id":4,
"tenant_id":2,
"primary_namespace":false,
"imported":false,
"snapshots":[
{
"id":"a44d6e3a108511ecb4620d978aa26f58",
"name":"u1ns1iquap_ss1u1ns1",
"description":"Namespace u1ns1 snapshot",
"state":"ONLINE",
"create_time":1631092696,
"size":0
}
],
"enabled_snap_schedule_summary":{
},
"repos":[
{
"name":"repo1",
"params":"{\"repo_params\":\"<REDACTED>\",\"bucket\":\"robin-pgsql\",\"path\":\"demo1\\\/\",\"permissions\":\"readwrite\"}"
}
],
"backups":[
{
"id":"a3b979f0108a11ec931c0d8a6d76a1ea",
"name":"u1ns1_nsbackup-1631094817",
"description":"-",
"state":"Pushed",
"create_time":1631094818,
"size":369098752
}
],
"enabled_backup_schedule_summary":{
},
"snapback":{
"snapshot":{
},
"backup":{
}
}
}
],
"network_policies":{
"u1ns1":[
]
}
}
9.3.3. Add a Namespace¶
In order to create a namespace or import an existing one and register it with Robin such that it can be used for future application deployments, issue the following command:
robin namespace add <name>
--username <username>
--tenant <tenant>
--import-namespace
|
Name of namespace to create |
|
Username of user to assign the namespace to. Default value is the current user |
|
Name of tenant the namespace will be bound to. Note the referenced user must be a member of that tenant |
|
Import an existing Kubernetes namespace |
Example:
# robin namespace add user1-ns
Namespace 'user1-ns' has been added for user 'user1' in tenant 't1'
# robin namespace list
+--------------+--------------+-------------------+
| Name | Owner/Tenant | Primary Namespace |
+--------------+--------------+-------------------+
| t002-u000005 | user1/t1 | True |
| user1-ns | user1/t1 | False |
+--------------+--------------+-------------------+
Creates/imports a namespace and registers it with Robin such that it can be used for future application deployments.
End Point: /api/v3/robin_server/namespaces
Method: POST
URL Parameters: None
Data Parameters:
name: <name>
- This mandatory field within the payload specifies the name of the namespace to be created.username: <username>
- Utilizing this parameter within the payload, by specifying the name of a user, results in the newly created namespace being assigned to the them. If not specified the current user is used.tenant: <tenant>
- Utilizing this parameter within the payload, by specifying the name of a tenant, results in the newly created namespace being bound to the aforementioned tenant. Note the user the namespace is assigned to must be a member of that tenant. If not specified the users current tenant will be used.import_namespace: true
- Utilizing this parameter within the payload results in an existing Kubernetes namespace being registered instead of a new namespace being created.
Port: RCM Port (default value is 29442)
Headers:
Authorization: <auth_token>
: Authorization token to identify which user is sending the request. The token can be acquired from the login API.
Success Response Code: 200
Error Response Code: 500 (Internal Server Error), 404 (Not Found Error), 401 (Unauthorized Error), 400 (Invalid Api Usage Error)
Example Response:
Output
{
"message": "Namespace 'user1-ns' has been added for user 'user1' in tenant 't1'"
}
9.3.4. Remove a Namespace¶
In order to delete or unregister a namespace with Robin such that it cannot be used for future application deployments, issue the following command:
robin namespace remove <name>
--keep-k8s-namespace
--force
--yes
|
Namespace name |
|
Keep (don’t delete) the associated Kubernetes namespace. |
|
Force removal of any user shares |
|
Do not prompt the user for confirmation |
Note
If you delete a namespace using the kubectl delete ns
command, it will not be deleted from Robin and will still be shown in the output of the robin namespace list
command. To delete it from Robin, the robin namespace remove
command must be used.
Example:
# robin namespace remove user1-ns
Are you sure you want to delete [y/n] ? y
Namespace 'user1-ns' has been removed
Deletes/unregisters a namespace with Robin such that it cannot be used for future application deployments.
End Point: /api/v3/robin_server/namespaces
Method: DELETE
URL Parameters: None
Data Parameters:
name: <name>
- This mandatory field within the payload specifies the name of the namespace to be deleted.delete: false
- Utilizing this parameter within the payload results in the associated namespace not being deleted. The default value is true.force: true
- Utilizing this parameter within the payload results in the forceful removal of any user shares of this namespace. The default value is false.
Port: RCM Port (default value is 29442)
Headers:
Authorization: <auth_token>
: Authorization token to identify which user is sending the request. The token can be acquired from the login API.
Success Response Code: 200
Error Response Code: 500 (Internal Server Error), 404 (Not Found Error), 401 (Unauthorized Error), 400 (Invalid Api Usage Error)
Example Response:
Output
{
"message": "Namespace 'user1-ns' has been removed"
}
9.3.6. Stop Sharing a Namespace¶
In order to unshare a namespace with a set of users and/or unassign operations the aforementioned users are allowed to perform on the namespace, issue the following command:
robin namespace unshare <name> [user_list]
--all-tenant-users
--operations OPERATIONS
|
Name of the namespace to share |
|
Optional comma separated list of users to stop sharing the namespace with |
|
Unshare the namespace with all tenant users |
|
Comma separated list of operations users will no longer be allowed to perform on the shared namespace. If no operations are specified, then sharing of the namespace with the specified users will be stopped. |
Example:
# robin namespace unshare t1-ns --all-tenant-users
Namespace 't1-ns' is no longer shared with all users of tenant 't1'
Note
The ability to stop sharing a namespace with users is subject to Role Based Access Control (RBAC). Only Cluster Administrators (users having the superadmin role) and Tenant Administrators (users having the tenantadmin role) have permission to do so. A namespace can only be unshared with users from the same tenant that it is bound to.
Unshares a namespace with a set of users and/or unassigns operations the aforementioned users are allowed to perform on the namespace.
End Point: /api/v3/robin_server/namespaces/<namespace_name>
Method: PUT
URL Parameters: None
Data Parameters:
action: user_unshare
- This mandatory field within the payload specifies that the user unshare operation is to be performed.user_list: <list_of_user_names>
- Utilizing this parameter within the payload, by specifiying a comma seperated list of usernames, results in the namespace being unshared with the respective users.operation_list: <list_of_operations>
- Utilizing this parameter within the payload, by specifying a comma seperated list of operations, results in the aforementioned users not being able to perform the given operations on the target namespace. To disallow all valid operations to be performed specify a list containing ‘ALL_OPERATIONS’. If no operations are specified, then sharing of the namespace with the specified users will be stopped.all_tenant_users: true
- Utilizing this parameter within the payload results in the namespace being unshared with all users of the given tenant. The default value is false.
Note
At least one of the following options, user_list
or all_tenant_users
, must be used in order to specify the users to unshare the namespace with. In addition to view a list of operations that can be unshared for the namespace object, review the section detailed here.
Port: RCM Port (default value is 29442)
Headers:
Authorization: <auth_token>
: Authorization token to identify which user is sending the request. The token can be acquired from the login API.
Success Response Code: 200
Error Response Code: 500 (Internal Server Error), 404 (Not Found Error), 401 (Unauthorized Error), 400 (Invalid Api Usage Error)
Example Response:
Output
{
"message": "Namespace 't1-ns' is no longer shared with all users of tenant 't1'"
}
9.3.8. Change Namespace Ownership¶
In order to transfer the ownership of a registered namespace from one user to another, issue the following command:
robin namespace change-owner <namespace> <username>
--no-app-transfer
|
Namespace name |
|
The username of the new owner |
|
Allow the original namespace owner to retain ownership of any apps they previously deployed to the namespace (the namespace will be shared with the original owner if it’s not already shared with all tenant users). Note that this option cannot be used when the namespace is a user’s primary namespace. |
Example:
root@cscale-82-64 ~]# robin namespace change-owner t1-ns user1 --wait
Job: 84 Name: NamespaceChangeOwner State: PROCESSED Error: 0
Job: 84 Name: NamespaceChangeOwner State: COMPLETED Error: 0
# robin namespace list t1-ns
+-------+--------------+-------------------+
| Name | Owner/Tenant | Primary Namespace |
+-------+--------------+-------------------+
| t1-ns | user1/t1 | False |
+-------+--------------+-------------------+
Note
The ability to change the owner of a namespace is subject to Role Based Access Control (RBAC). Only Cluster Administrators (users having the superadmin role) and Tenant Administrators (users having the tenantadmin role) have permission to do so.
A namespace can only be shared with users that are members of the tenant it is bound to.
By default, the original owner of a namespace will lose access
to the namespace when ownership has been reassigned. If they have
any applications deployed to the namespace, then ownership of the
applications will transfer to the new owner of the namespace. To
allow the original namespace owner to retain ownership of their
apps, include --no-app-transfer
on the command line. This
causes the namespace to be shared with its original owner, so they
can continue to access it.
Transfers the ownership of a registered namespace from one user to another.
End Point: /api/v3/robin_server/namespaces/<namespace_name>
Method: PUT
URL Parameters: None
Data Parameters:
action: change_owner
- This mandatory field within the payload specifies that the change owner operation is to be performed.username: <username>
- This mandatory field within the payload specifies that the name of the user who ownership of the namespace will be transferred to.no_app_transfer: true
- Utilizing this parameter within the payload results in the original namespace owner to retain ownership of any apps they previously deployed to the namespace. The default value is false.
Port: RCM Port (default value is 29442)
Headers:
Authorization: <auth_token>
: Authorization token to identify which user is sending the request. The token can be acquired from the login API.
Success Response Code: 202
Error Response Code: 500 (Internal Server Error), 404 (Not Found Error), 401 (Unauthorized Error), 400 (Invalid Api Usage Error)
Example Response:
Output
{
"jobid":87
}