@catladder/cli 1.15.0 → 1.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apps/cli/commands/project/commandSetup.js +5 -200
- package/dist/apps/cli/commands/project/commandSetup.js.map +1 -1
- package/dist/apps/cli/commands/project/setup/index.d.ts +2 -0
- package/dist/apps/cli/commands/project/setup/index.js +103 -0
- package/dist/apps/cli/commands/project/setup/index.js.map +1 -0
- package/dist/apps/cli/commands/project/setup/setupAccessTokens.d.ts +2 -0
- package/dist/apps/cli/commands/project/setup/setupAccessTokens.js +106 -0
- package/dist/apps/cli/commands/project/setup/setupAccessTokens.js.map +1 -0
- package/dist/apps/cli/commands/project/setup/setupContext.d.ts +3 -0
- package/dist/apps/cli/commands/project/setup/setupContext.js +74 -0
- package/dist/apps/cli/commands/project/setup/setupContext.js.map +1 -0
- package/dist/apps/cli/commands/project/setup/setupKubernetes.d.ts +3 -0
- package/dist/apps/cli/commands/project/setup/setupKubernetes.js +132 -0
- package/dist/apps/cli/commands/project/setup/setupKubernetes.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/apps/cli/commands/project/commandSetup.ts +2 -230
- package/src/apps/cli/commands/project/setup/index.ts +42 -0
- package/src/apps/cli/commands/project/setup/setupAccessTokens.ts +70 -0
- package/src/apps/cli/commands/project/setup/setupContext.ts +37 -0
- package/src/apps/cli/commands/project/setup/setupKubernetes.ts +112 -0
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"catladder": "./bin/catladder"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@catladder/pipeline": "1.
|
|
19
|
+
"@catladder/pipeline": "1.16.1",
|
|
20
20
|
"@kubernetes/client-node": "^0.16.2",
|
|
21
21
|
"child-process-promise": "^2.2.1",
|
|
22
22
|
"command-exists-promise": "^2.0.2",
|
|
@@ -55,5 +55,5 @@
|
|
|
55
55
|
"eslint": "^8.7.0",
|
|
56
56
|
"typescript": "^4.5.4"
|
|
57
57
|
},
|
|
58
|
-
"version": "1.
|
|
58
|
+
"version": "1.16.1"
|
|
59
59
|
}
|
|
@@ -1,19 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getFullKubernetesClusterName,
|
|
3
|
-
isOfDeployType,
|
|
4
|
-
} from "@catladder/pipeline";
|
|
5
1
|
import Vorpal from "vorpal";
|
|
6
|
-
import {
|
|
7
|
-
import { getAllPipelineContexts } from "../../../../config/getProjectConfig";
|
|
8
|
-
import { connectToCluster } from "../../../../utils/cluster";
|
|
9
|
-
import {
|
|
10
|
-
doGitlabRequest,
|
|
11
|
-
getProjectInfo,
|
|
12
|
-
upsertAllVariables,
|
|
13
|
-
} from "../../../../utils/gitlab";
|
|
14
|
-
import ensureNamespace from "./utils/ensureNamespace";
|
|
15
|
-
import open from "open";
|
|
16
|
-
import { projectConfigSecrets } from "./commandConfigSecrets";
|
|
2
|
+
import { setupProject } from "./setup";
|
|
17
3
|
|
|
18
4
|
export default async (vorpal: Vorpal) =>
|
|
19
5
|
vorpal
|
|
@@ -22,219 +8,5 @@ export default async (vorpal: Vorpal) =>
|
|
|
22
8
|
"Initializes all environments and creates requires resources, service accounts, etc."
|
|
23
9
|
)
|
|
24
10
|
.action(async function () {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
for (const context of allContext) {
|
|
28
|
-
this.log("");
|
|
29
|
-
this.log(
|
|
30
|
-
"=================================================================================="
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
this.log(
|
|
34
|
-
"setting up " +
|
|
35
|
-
context.environment.shortName +
|
|
36
|
-
":" +
|
|
37
|
-
context.componentName +
|
|
38
|
-
"..."
|
|
39
|
-
);
|
|
40
|
-
this.log("");
|
|
41
|
-
const deployConfig = context.componentConfig.deploy;
|
|
42
|
-
if (isOfDeployType(deployConfig, "kubernetes")) {
|
|
43
|
-
const fullName = getFullKubernetesClusterName(deployConfig.cluster);
|
|
44
|
-
this.log(`cluster: ${fullName}`);
|
|
45
|
-
|
|
46
|
-
await connectToCluster(fullName);
|
|
47
|
-
this.log("");
|
|
48
|
-
this.log("ensuring namespace ...");
|
|
49
|
-
const namespace = await ensureNamespace(context);
|
|
50
|
-
this.log("Namespace " + namespace + " created / updated!");
|
|
51
|
-
this.log("");
|
|
52
|
-
//$.verbose = true;
|
|
53
|
-
|
|
54
|
-
// we name the service account and the role and the role binding with the same name
|
|
55
|
-
// we currently create one per component to better separate them
|
|
56
|
-
this.log("ensuring service accounts...");
|
|
57
|
-
const serviceAccountName = `cl-${context.componentName}-deploy`;
|
|
58
|
-
const KUBE_URL =
|
|
59
|
-
await $`TERM=dumb kubectl cluster-info | grep -E 'Kubernetes master|Kubernetes control plane' | awk '/http/ {print $NF}'`.then(
|
|
60
|
-
(s) => s.stdout.trim()
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
// first upsert service acount in the ns
|
|
64
|
-
try {
|
|
65
|
-
await $`kubectl delete serviceaccount --namespace ${namespace} ${serviceAccountName}`;
|
|
66
|
-
await $`kubectl delete rolebinding --namespace ${namespace} ${serviceAccountName}`;
|
|
67
|
-
await $`kubectl delete role --namespace ${namespace} ${serviceAccountName}`;
|
|
68
|
-
} catch (e) {
|
|
69
|
-
// ignore
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
await $`kubectl create serviceaccount --namespace ${namespace} ${serviceAccountName}`;
|
|
73
|
-
|
|
74
|
-
// upsert role in the ns
|
|
75
|
-
|
|
76
|
-
await $`cat <<EOF | kubectl apply -f -
|
|
77
|
-
kind: Role
|
|
78
|
-
apiVersion: rbac.authorization.k8s.io/v1
|
|
79
|
-
metadata:
|
|
80
|
-
namespace: ${namespace}
|
|
81
|
-
name: ${serviceAccountName}
|
|
82
|
-
rules:
|
|
83
|
-
- apiGroups: ["", "extensions", "apps", "networking.k8s.io", "batch"]
|
|
84
|
-
resources: ["deployments", "replicasets", "statefulsets", "pods", "secrets", "configmaps", "services", "ingresses", "serviceaccounts", "jobs", "cronjobs"]
|
|
85
|
-
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # You can also use ["*"]
|
|
86
|
-
---
|
|
87
|
-
kind: RoleBinding
|
|
88
|
-
apiVersion: rbac.authorization.k8s.io/v1
|
|
89
|
-
metadata:
|
|
90
|
-
name: ${serviceAccountName}
|
|
91
|
-
namespace: ${namespace}
|
|
92
|
-
subjects:
|
|
93
|
-
- kind: ServiceAccount
|
|
94
|
-
name: ${serviceAccountName}
|
|
95
|
-
namespace: ${namespace}
|
|
96
|
-
roleRef:
|
|
97
|
-
kind: Role
|
|
98
|
-
name: ${serviceAccountName}
|
|
99
|
-
apiGroup: rbac.authorization.k8s.io
|
|
100
|
-
EOF
|
|
101
|
-
`;
|
|
102
|
-
|
|
103
|
-
// get token name
|
|
104
|
-
const tokenName =
|
|
105
|
-
await $`kubectl get serviceaccount --namespace ${namespace} ${serviceAccountName} -o jsonpath='{.secrets[0].name}'`;
|
|
106
|
-
|
|
107
|
-
const KUBE_CA_PEM =
|
|
108
|
-
await $`kubectl get secret ${tokenName} --namespace ${namespace} -o jsonpath="{['data']['ca\\.crt']}"`.then(
|
|
109
|
-
(c) => c.stdout.trim()
|
|
110
|
-
);
|
|
111
|
-
const KUBE_TOKEN =
|
|
112
|
-
await $`kubectl get secret ${tokenName} --namespace ${namespace} -o jsonpath="{['data']['token']}" | base64 --decode`.then(
|
|
113
|
-
(c) => c.stdout.trim()
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
const vars = {
|
|
117
|
-
KUBE_TOKEN,
|
|
118
|
-
KUBE_CA_PEM,
|
|
119
|
-
KUBE_URL,
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
this.log("service accounts created / updated!");
|
|
123
|
-
|
|
124
|
-
this.log("");
|
|
125
|
-
this.log("pusing secrets to gitlab...");
|
|
126
|
-
|
|
127
|
-
await upsertAllVariables(
|
|
128
|
-
this,
|
|
129
|
-
vars,
|
|
130
|
-
context.environment.shortName,
|
|
131
|
-
context.componentName
|
|
132
|
-
);
|
|
133
|
-
this.log("done!");
|
|
134
|
-
}
|
|
135
|
-
this.log("");
|
|
136
|
-
this.log(
|
|
137
|
-
"✅ " +
|
|
138
|
-
context.environment.shortName +
|
|
139
|
-
":" +
|
|
140
|
-
context.componentName +
|
|
141
|
-
" done!"
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
this.log("");
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const { id: projectId, web_url: projectWebUrl } = await getProjectInfo(
|
|
148
|
-
this
|
|
149
|
-
);
|
|
150
|
-
const variables = await doGitlabRequest(
|
|
151
|
-
this,
|
|
152
|
-
`projects/${projectId}/variables`
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
if (!variables.find((v: any) => v.key === "GL_TOKEN")) {
|
|
156
|
-
this.log(
|
|
157
|
-
"I need add a GL_TOKEN to the project, so that semantic release will work\n"
|
|
158
|
-
);
|
|
159
|
-
this.log(
|
|
160
|
-
"👉 Please please create a project access token in gitlab and copy its value into clipboard\n\n - name: something like 'semantic-release'\n - expires: leave empty\n - scopes: api, read_repository"
|
|
161
|
-
);
|
|
162
|
-
this.log("\n");
|
|
163
|
-
|
|
164
|
-
const { understood } = await this.prompt({
|
|
165
|
-
default: true,
|
|
166
|
-
message: "Understood and open gitlab now? 🤔",
|
|
167
|
-
name: "understood",
|
|
168
|
-
type: "confirm",
|
|
169
|
-
});
|
|
170
|
-
if (!understood) {
|
|
171
|
-
this.log("continuing anyway...");
|
|
172
|
-
}
|
|
173
|
-
open(`${projectWebUrl}/-/settings/access_tokens`);
|
|
174
|
-
|
|
175
|
-
this.log("\n");
|
|
176
|
-
|
|
177
|
-
this.log("Enter your copied token now: ");
|
|
178
|
-
|
|
179
|
-
this.log("\n");
|
|
180
|
-
const { GL_TOKEN } = await this.prompt({
|
|
181
|
-
type: "password",
|
|
182
|
-
name: "GL_TOKEN",
|
|
183
|
-
message: "Access Token: ",
|
|
184
|
-
});
|
|
185
|
-
await doGitlabRequest(this, `projects/${projectId}/variables`, {
|
|
186
|
-
key: "GL_TOKEN",
|
|
187
|
-
value: GL_TOKEN,
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const deploy_tokens = await doGitlabRequest(
|
|
192
|
-
this,
|
|
193
|
-
`projects/${projectId}/deploy_tokens`
|
|
194
|
-
);
|
|
195
|
-
|
|
196
|
-
if (
|
|
197
|
-
!deploy_tokens.find(
|
|
198
|
-
(v: { name: string }) => v.name === "gitlab-deploy-token"
|
|
199
|
-
)
|
|
200
|
-
) {
|
|
201
|
-
this.log(
|
|
202
|
-
"I will setup the 'GitLab Deploy Token', so Kubernetes can pull images from this project."
|
|
203
|
-
);
|
|
204
|
-
|
|
205
|
-
await doGitlabRequest(this, `projects/${projectId}/deploy_tokens`, {
|
|
206
|
-
id: projectId,
|
|
207
|
-
name: "gitlab-deploy-token",
|
|
208
|
-
scopes: ["read_registry"],
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
this.log();
|
|
212
|
-
const { configSecrets } = await this.prompt({
|
|
213
|
-
default: true,
|
|
214
|
-
message:
|
|
215
|
-
"Before deployments work, you need to config secrets. Do it now?",
|
|
216
|
-
name: "configSecrets",
|
|
217
|
-
type: "confirm",
|
|
218
|
-
});
|
|
219
|
-
this.log();
|
|
220
|
-
if (configSecrets) {
|
|
221
|
-
await projectConfigSecrets(this);
|
|
222
|
-
} else {
|
|
223
|
-
this.log(
|
|
224
|
-
"👆 don't forget to config secret using `project-config-secrets`"
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
this.log();
|
|
228
|
-
this.log("gitlab is ready! 🥂");
|
|
229
|
-
this.log("\n");
|
|
230
|
-
this.log("do not forget to make sure that:");
|
|
231
|
-
[
|
|
232
|
-
"you have __health route in place",
|
|
233
|
-
"lint and test are defined",
|
|
234
|
-
"secrets are configured (call project-config-secret)",
|
|
235
|
-
"eat your vegetables",
|
|
236
|
-
"be awesome 🤩",
|
|
237
|
-
].forEach((tip) => this.log(` - ${tip}`));
|
|
238
|
-
this.log("\n");
|
|
239
|
-
this.log("\n");
|
|
11
|
+
await setupProject(this);
|
|
240
12
|
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { CommandInstance } from "vorpal";
|
|
2
|
+
import { getAllPipelineContexts } from "../../../../../config/getProjectConfig";
|
|
3
|
+
import { projectConfigSecrets } from "../commandConfigSecrets";
|
|
4
|
+
import { setupAccessTokens } from "./setupAccessTokens";
|
|
5
|
+
import { setupContext } from "./setupContext";
|
|
6
|
+
|
|
7
|
+
export const setupProject = async (instance: CommandInstance) => {
|
|
8
|
+
const allContext = await getAllPipelineContexts();
|
|
9
|
+
|
|
10
|
+
for (const context of allContext) {
|
|
11
|
+
await setupContext(instance, context);
|
|
12
|
+
}
|
|
13
|
+
await setupAccessTokens(instance);
|
|
14
|
+
instance.log("");
|
|
15
|
+
const { configSecrets } = await instance.prompt({
|
|
16
|
+
default: true,
|
|
17
|
+
message: "Before deployments work, you need to config secrets. Do it now?",
|
|
18
|
+
name: "configSecrets",
|
|
19
|
+
type: "confirm",
|
|
20
|
+
});
|
|
21
|
+
instance.log("");
|
|
22
|
+
if (configSecrets) {
|
|
23
|
+
await projectConfigSecrets(instance);
|
|
24
|
+
} else {
|
|
25
|
+
instance.log(
|
|
26
|
+
"👆 don't forget to config secret using `project-config-secrets`"
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
instance.log("");
|
|
30
|
+
instance.log("gitlab is ready! 🥂");
|
|
31
|
+
instance.log("\n");
|
|
32
|
+
instance.log("do not forget to make sure that:");
|
|
33
|
+
[
|
|
34
|
+
"you have __health route in place",
|
|
35
|
+
"lint and test are defined",
|
|
36
|
+
"secrets are configured (call project-config-secret)",
|
|
37
|
+
"eat your vegetables",
|
|
38
|
+
"be awesome 🤩",
|
|
39
|
+
].forEach((tip) => instance.log(` - ${tip}`));
|
|
40
|
+
instance.log("\n");
|
|
41
|
+
instance.log("\n");
|
|
42
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import open from "open";
|
|
2
|
+
import { CommandInstance } from "vorpal";
|
|
3
|
+
import { doGitlabRequest, getProjectInfo } from "../../../../../utils/gitlab";
|
|
4
|
+
|
|
5
|
+
export const setupAccessTokens = async (instance: CommandInstance) => {
|
|
6
|
+
const { id: projectId, web_url: projectWebUrl } = await getProjectInfo(
|
|
7
|
+
instance
|
|
8
|
+
);
|
|
9
|
+
const variables = await doGitlabRequest(
|
|
10
|
+
instance,
|
|
11
|
+
`projects/${projectId}/variables`
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
if (!variables.find((v: any) => v.key === "GL_TOKEN")) {
|
|
15
|
+
instance.log(
|
|
16
|
+
"I need add a GL_TOKEN to the project, so that semantic release will work\n"
|
|
17
|
+
);
|
|
18
|
+
instance.log(
|
|
19
|
+
"👉 Please please create a project access token in gitlab and copy its value into clipboard\n\n - name: something like 'semantic-release'\n - expires: leave empty\n - scopes: api, read_repository"
|
|
20
|
+
);
|
|
21
|
+
instance.log("\n");
|
|
22
|
+
|
|
23
|
+
const { understood } = await instance.prompt({
|
|
24
|
+
default: true,
|
|
25
|
+
message: "Understood and open gitlab now? 🤔",
|
|
26
|
+
name: "understood",
|
|
27
|
+
type: "confirm",
|
|
28
|
+
});
|
|
29
|
+
if (!understood) {
|
|
30
|
+
instance.log("continuing anyway...");
|
|
31
|
+
}
|
|
32
|
+
open(`${projectWebUrl}/-/settings/access_tokens`);
|
|
33
|
+
|
|
34
|
+
instance.log("\n");
|
|
35
|
+
|
|
36
|
+
instance.log("Enter your copied token now: ");
|
|
37
|
+
|
|
38
|
+
instance.log("\n");
|
|
39
|
+
const { GL_TOKEN } = await instance.prompt({
|
|
40
|
+
type: "password",
|
|
41
|
+
name: "GL_TOKEN",
|
|
42
|
+
message: "Access Token: ",
|
|
43
|
+
});
|
|
44
|
+
await doGitlabRequest(instance, `projects/${projectId}/variables`, {
|
|
45
|
+
key: "GL_TOKEN",
|
|
46
|
+
value: GL_TOKEN,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const deploy_tokens = await doGitlabRequest(
|
|
51
|
+
instance,
|
|
52
|
+
`projects/${projectId}/deploy_tokens`
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
if (
|
|
56
|
+
!deploy_tokens.find(
|
|
57
|
+
(v: { name: string }) => v.name === "gitlab-deploy-token"
|
|
58
|
+
)
|
|
59
|
+
) {
|
|
60
|
+
instance.log(
|
|
61
|
+
"I will setup the 'GitLab Deploy Token', so Kubernetes can pull images from this project."
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
await doGitlabRequest(instance, `projects/${projectId}/deploy_tokens`, {
|
|
65
|
+
id: projectId,
|
|
66
|
+
name: "gitlab-deploy-token",
|
|
67
|
+
scopes: ["read_registry"],
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Context, isOfDeployType } from "@catladder/pipeline";
|
|
2
|
+
import { CommandInstance } from "vorpal";
|
|
3
|
+
import { setupKubernetes } from "./setupKubernetes";
|
|
4
|
+
|
|
5
|
+
export const setupContext = async (
|
|
6
|
+
instance: CommandInstance,
|
|
7
|
+
context: Context
|
|
8
|
+
) => {
|
|
9
|
+
instance.log("");
|
|
10
|
+
instance.log(
|
|
11
|
+
"=================================================================================="
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
instance.log(
|
|
15
|
+
"🐱 🔧 setting up " +
|
|
16
|
+
context.environment.shortName +
|
|
17
|
+
":" +
|
|
18
|
+
context.componentName +
|
|
19
|
+
"..."
|
|
20
|
+
);
|
|
21
|
+
instance.log("");
|
|
22
|
+
const deployConfig = context.componentConfig.deploy;
|
|
23
|
+
if (isOfDeployType(deployConfig, "kubernetes")) {
|
|
24
|
+
await setupKubernetes(instance, context);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
instance.log("");
|
|
28
|
+
instance.log(
|
|
29
|
+
"✅ " +
|
|
30
|
+
context.environment.shortName +
|
|
31
|
+
":" +
|
|
32
|
+
context.componentName +
|
|
33
|
+
" done!"
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
instance.log("");
|
|
37
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Context,
|
|
3
|
+
getFullKubernetesClusterName,
|
|
4
|
+
isOfDeployType,
|
|
5
|
+
} from "@catladder/pipeline";
|
|
6
|
+
import { CommandInstance } from "vorpal";
|
|
7
|
+
import { $ } from "zx";
|
|
8
|
+
import { connectToCluster } from "../../../../../utils/cluster";
|
|
9
|
+
import { upsertAllVariables } from "../../../../../utils/gitlab";
|
|
10
|
+
import ensureNamespace from "../utils/ensureNamespace";
|
|
11
|
+
|
|
12
|
+
export const setupKubernetes = async (
|
|
13
|
+
instance: CommandInstance,
|
|
14
|
+
context: Context
|
|
15
|
+
) => {
|
|
16
|
+
const deployConfig = context.componentConfig.deploy;
|
|
17
|
+
if (!isOfDeployType(deployConfig, "kubernetes")) {
|
|
18
|
+
throw new Error("cannot run setupKubernetes on non-kubernetes deployments");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const fullName = getFullKubernetesClusterName(deployConfig.cluster);
|
|
22
|
+
instance.log(`cluster: ${fullName}`);
|
|
23
|
+
|
|
24
|
+
await connectToCluster(fullName);
|
|
25
|
+
instance.log("");
|
|
26
|
+
instance.log("ensuring namespace ...");
|
|
27
|
+
const namespace = await ensureNamespace(context);
|
|
28
|
+
instance.log("Namespace " + namespace + " created / updated!");
|
|
29
|
+
instance.log("");
|
|
30
|
+
//$.verbose = true;
|
|
31
|
+
|
|
32
|
+
// we name the service account and the role and the role binding with the same name
|
|
33
|
+
// we currently create one per component to better separate them
|
|
34
|
+
instance.log("ensuring service accounts...");
|
|
35
|
+
const serviceAccountName = `cl-${context.componentName}-deploy`;
|
|
36
|
+
const KUBE_URL =
|
|
37
|
+
await $`TERM=dumb kubectl cluster-info | grep -E 'Kubernetes master|Kubernetes control plane' | awk '/http/ {print $NF}'`.then(
|
|
38
|
+
(s) => s.stdout.trim()
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
// first upsert service acount in the ns
|
|
42
|
+
try {
|
|
43
|
+
await $`kubectl delete serviceaccount --namespace ${namespace} ${serviceAccountName}`;
|
|
44
|
+
await $`kubectl delete rolebinding --namespace ${namespace} ${serviceAccountName}`;
|
|
45
|
+
await $`kubectl delete role --namespace ${namespace} ${serviceAccountName}`;
|
|
46
|
+
} catch (e) {
|
|
47
|
+
// ignore
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
await $`kubectl create serviceaccount --namespace ${namespace} ${serviceAccountName}`;
|
|
51
|
+
|
|
52
|
+
// upsert role in the ns
|
|
53
|
+
|
|
54
|
+
await $`cat <<EOF | kubectl apply -f -
|
|
55
|
+
kind: Role
|
|
56
|
+
apiVersion: rbac.authorization.k8s.io/v1
|
|
57
|
+
metadata:
|
|
58
|
+
namespace: ${namespace}
|
|
59
|
+
name: ${serviceAccountName}
|
|
60
|
+
rules:
|
|
61
|
+
- apiGroups: ["", "extensions", "apps", "networking.k8s.io", "batch"]
|
|
62
|
+
resources: ["deployments", "replicasets", "statefulsets", "pods", "secrets", "configmaps", "services", "ingresses", "serviceaccounts", "jobs", "cronjobs"]
|
|
63
|
+
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # You can also use ["*"]
|
|
64
|
+
---
|
|
65
|
+
kind: RoleBinding
|
|
66
|
+
apiVersion: rbac.authorization.k8s.io/v1
|
|
67
|
+
metadata:
|
|
68
|
+
name: ${serviceAccountName}
|
|
69
|
+
namespace: ${namespace}
|
|
70
|
+
subjects:
|
|
71
|
+
- kind: ServiceAccount
|
|
72
|
+
name: ${serviceAccountName}
|
|
73
|
+
namespace: ${namespace}
|
|
74
|
+
roleRef:
|
|
75
|
+
kind: Role
|
|
76
|
+
name: ${serviceAccountName}
|
|
77
|
+
apiGroup: rbac.authorization.k8s.io
|
|
78
|
+
EOF
|
|
79
|
+
`;
|
|
80
|
+
|
|
81
|
+
// get token name
|
|
82
|
+
const tokenName =
|
|
83
|
+
await $`kubectl get serviceaccount --namespace ${namespace} ${serviceAccountName} -o jsonpath='{.secrets[0].name}'`;
|
|
84
|
+
|
|
85
|
+
const KUBE_CA_PEM =
|
|
86
|
+
await $`kubectl get secret ${tokenName} --namespace ${namespace} -o jsonpath="{['data']['ca\\.crt']}"`.then(
|
|
87
|
+
(c) => c.stdout.trim()
|
|
88
|
+
);
|
|
89
|
+
const KUBE_TOKEN =
|
|
90
|
+
await $`kubectl get secret ${tokenName} --namespace ${namespace} -o jsonpath="{['data']['token']}" | base64 --decode`.then(
|
|
91
|
+
(c) => c.stdout.trim()
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const vars = {
|
|
95
|
+
KUBE_TOKEN,
|
|
96
|
+
KUBE_CA_PEM,
|
|
97
|
+
KUBE_URL,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
instance.log("service accounts created / updated!");
|
|
101
|
+
|
|
102
|
+
instance.log("");
|
|
103
|
+
instance.log("pusing secrets to gitlab...");
|
|
104
|
+
|
|
105
|
+
await upsertAllVariables(
|
|
106
|
+
instance,
|
|
107
|
+
vars,
|
|
108
|
+
context.environment.shortName,
|
|
109
|
+
context.componentName
|
|
110
|
+
);
|
|
111
|
+
instance.log("done!");
|
|
112
|
+
};
|