@abgov/nx-oc 12.8.0 → 12.10.0

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/generators.json CHANGED
@@ -22,6 +22,11 @@
22
22
  "factory": "./src/generators/deployment/deployment",
23
23
  "schema": "./src/generators/deployment/schema.json",
24
24
  "description": "Generator that creates OpenShift manifests for project deployment."
25
+ },
26
+ "sandbox": {
27
+ "factory": "./src/generators/sandbox/sandbox",
28
+ "schema": "./src/generators/sandbox/schema.json",
29
+ "description": "Generator that creates a sandbox deployment for rapid local iteration (local build, push to OC internal registry)."
25
30
  }
26
31
  }
27
32
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abgov/nx-oc",
3
- "version": "12.8.0",
3
+ "version": "12.10.0",
4
4
  "license": "Apache-2.0",
5
5
  "main": "src/index.js",
6
6
  "description": "Government of Alberta - Nx plugin for OpenShift.",
@@ -50,8 +50,8 @@ function normalizeOptions(host, options) {
50
50
  });
51
51
  }
52
52
  function addFiles(host, options) {
53
- var _a;
54
- const templateOptions = Object.assign(Object.assign(Object.assign({}, options), options.adsp), { sourceRepositoryUrl: (0, git_utils_1.getGitRemoteUrl)(), database: (_a = options.database) !== null && _a !== void 0 ? _a : 'none', tmpl: '' });
53
+ var _a, _b;
54
+ const templateOptions = Object.assign(Object.assign(Object.assign({}, options), options.adsp), { sourceRepositoryUrl: (0, git_utils_1.getGitRemoteUrl)(), database: (_a = options.database) !== null && _a !== void 0 ? _a : 'none', sandbox: (_b = options.sandbox) !== null && _b !== void 0 ? _b : false, tmpl: '' });
55
55
  (0, devkit_1.generateFiles)(host, path.join(__dirname, `${options.appType}-files`), `./.openshift/${options.projectName}`, templateOptions);
56
56
  }
57
57
  function default_1(host, options) {
@@ -1 +1 @@
1
- {"version":3,"file":"deployment.js","sourceRoot":"","sources":["../../../../../../packages/nx-oc/src/generators/deployment/deployment.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deployment.js","sourceRoot":"","sources":["../../../../../../packages/nx-oc/src/generators/deployment/deployment.ts"],"names":[],"mappings":"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"}
@@ -90,6 +90,10 @@ describe('Deployment Generator', () => {
90
90
 
91
91
  const dockerfile = host.read('.openshift/test/Dockerfile').toString();
92
92
  expect(dockerfile).toContain('nginx');
93
+
94
+ const manifest = host.read('.openshift/test/test.yml').toString();
95
+ expect(manifest).toContain('readinessProbe');
96
+ expect(manifest).toContain('livenessProbe');
93
97
  });
94
98
 
95
99
  it('can generate deployment for angular', async () => {
@@ -150,6 +154,10 @@ describe('Deployment Generator', () => {
150
154
 
151
155
  const dockerfile = host.read('.openshift/test/Dockerfile').toString();
152
156
  expect(dockerfile).toContain('node');
157
+
158
+ const manifest = host.read('.openshift/test/test.yml').toString();
159
+ expect(manifest).toContain('readinessProbe');
160
+ expect(manifest).toContain('livenessProbe');
153
161
  });
154
162
 
155
163
  it('can generate deployment for dotnet', async () => {
@@ -178,6 +186,10 @@ describe('Deployment Generator', () => {
178
186
 
179
187
  const dockerfile = host.read('.openshift/test/Dockerfile').toString();
180
188
  expect(dockerfile).toContain('dotnet');
189
+
190
+ const manifest = host.read('.openshift/test/test.yml').toString();
191
+ expect(manifest).toContain('readinessProbe');
192
+ expect(manifest).toContain('livenessProbe');
181
193
  });
182
194
 
183
195
  it('includes DATABASE_URL secretKeyRef and init container for postgres node deployment', async () => {
@@ -5,11 +5,13 @@ metadata:
5
5
  labels:
6
6
  app: <%= projectName %>
7
7
  parameters:
8
+ <% if (!sandbox) { %>
8
9
  - name: INFRA_PROJECT
9
10
  description: Project used for build infrastructure.
10
11
  displayName: Infrastructure Project
11
12
  value: <%= ocInfraProject %>
12
13
  required: true
14
+ <% } %>
13
15
  - name: PROJECT
14
16
  description: Project to deploy into.
15
17
  displayName: Project
@@ -19,17 +21,21 @@ parameters:
19
21
  displayName: Application Name
20
22
  value: <%= projectName %>
21
23
  required: true
24
+ <% if (!sandbox) { %>
22
25
  - name: DEPLOY_TAG
23
26
  description: ImageStream tag to deploy.
24
27
  displayName: Deploy Tag
25
28
  value: latest
26
29
  required: true
30
+ <% } %>
27
31
  objects:
32
+ <% if (!sandbox) { %>
28
33
  - apiVersion: image.openshift.io/v1
29
34
  kind: ImageStream
30
35
  metadata:
31
36
  name: ${APP_NAME}
32
37
  namespace: ${INFRA_PROJECT}
38
+ <% } %>
33
39
  - apiVersion: v1
34
40
  kind: ConfigMap
35
41
  metadata:
@@ -61,6 +67,7 @@ objects:
61
67
  metadata:
62
68
  name: ${APP_NAME}
63
69
  namespace: ${PROJECT}
70
+ <% if (!sandbox) { %>
64
71
  annotations:
65
72
  image.openshift.io/triggers: |-
66
73
  [
@@ -74,6 +81,7 @@ objects:
74
81
  "paused": true
75
82
  }
76
83
  ]
84
+ <% } %>
77
85
  spec:
78
86
  replicas: 1
79
87
  selector:
@@ -93,14 +101,18 @@ objects:
93
101
  spec:
94
102
  containers:
95
103
  - name: ${APP_NAME}
104
+ <% if (sandbox) { %>
105
+ image: image-registry.openshift-image-registry.svc:5000/${PROJECT}/<%= projectName %>:sandbox
106
+ <% } else { %>
96
107
  image: ${APP_NAME}:${DEPLOY_TAG}
108
+ <% } %>
97
109
  envFrom:
98
110
  - configMapRef:
99
111
  name: ${APP_NAME}
100
112
  env:
101
113
  - name: LOG_LEVEL
102
114
  value: info
103
- imagePullPolicy: IfNotPresent
115
+ imagePullPolicy: <%= sandbox ? 'Always' : 'IfNotPresent' %>
104
116
  ports:
105
117
  - containerPort: 5000
106
118
  name: http
@@ -112,6 +124,20 @@ objects:
112
124
  requests:
113
125
  cpu: 20m
114
126
  memory: 200Mi
127
+ readinessProbe:
128
+ httpGet:
129
+ path: /health
130
+ port: 5000
131
+ initialDelaySeconds: 10
132
+ periodSeconds: 10
133
+ failureThreshold: 3
134
+ livenessProbe:
135
+ httpGet:
136
+ path: /health
137
+ port: 5000
138
+ initialDelaySeconds: 30
139
+ periodSeconds: 30
140
+ failureThreshold: 3
115
141
  volumeMounts:
116
142
  - mountPath: /opt/app-root/app/appsettings.json
117
143
  name: config-volume
@@ -5,11 +5,13 @@ metadata:
5
5
  labels:
6
6
  app: <%= projectName %>
7
7
  parameters:
8
+ <% if (!sandbox) { %>
8
9
  - name: INFRA_PROJECT
9
10
  description: Project used for build infrastructure.
10
11
  displayName: Infrastructure Project
11
12
  value: <%= ocInfraProject %>
12
13
  required: true
14
+ <% } %>
13
15
  - name: PROJECT
14
16
  description: Project to deploy into.
15
17
  displayName: Project
@@ -19,17 +21,21 @@ parameters:
19
21
  displayName: Application Name
20
22
  value: <%= projectName %>
21
23
  required: true
24
+ <% if (!sandbox) { %>
22
25
  - name: DEPLOY_TAG
23
26
  description: ImageStream tag to deploy.
24
27
  displayName: Deploy Tag
25
28
  value: latest
26
29
  required: true
30
+ <% } %>
27
31
  objects:
32
+ <% if (!sandbox) { %>
28
33
  - apiVersion: image.openshift.io/v1
29
34
  kind: ImageStream
30
35
  metadata:
31
36
  name: ${APP_NAME}
32
37
  namespace: ${INFRA_PROJECT}
38
+ <% } %>
33
39
  - apiVersion: v1
34
40
  kind: ConfigMap
35
41
  metadata:
@@ -51,6 +57,7 @@ objects:
51
57
  metadata:
52
58
  name: ${APP_NAME}
53
59
  namespace: ${PROJECT}
60
+ <% if (!sandbox) { %>
54
61
  annotations:
55
62
  image.openshift.io/triggers: |-
56
63
  [
@@ -64,6 +71,7 @@ objects:
64
71
  "paused": true
65
72
  }
66
73
  ]
74
+ <% } %>
67
75
  spec:
68
76
  replicas: 1
69
77
  selector:
@@ -83,8 +91,12 @@ objects:
83
91
  spec:
84
92
  containers:
85
93
  - name: ${APP_NAME}
94
+ <% if (sandbox) { %>
95
+ image: image-registry.openshift-image-registry.svc:5000/${PROJECT}/<%= projectName %>:sandbox
96
+ <% } else { %>
86
97
  image: ${APP_NAME}:${DEPLOY_TAG}
87
- imagePullPolicy: IfNotPresent
98
+ <% } %>
99
+ imagePullPolicy: <%= sandbox ? 'Always' : 'IfNotPresent' %>
88
100
  ports:
89
101
  - containerPort: 8080
90
102
  name: http
@@ -96,6 +108,20 @@ objects:
96
108
  requests:
97
109
  cpu: 20m
98
110
  memory: 50Mi
111
+ readinessProbe:
112
+ httpGet:
113
+ path: /
114
+ port: 8080
115
+ initialDelaySeconds: 10
116
+ periodSeconds: 10
117
+ failureThreshold: 3
118
+ livenessProbe:
119
+ httpGet:
120
+ path: /
121
+ port: 8080
122
+ initialDelaySeconds: 30
123
+ periodSeconds: 30
124
+ failureThreshold: 3
99
125
  volumeMounts:
100
126
  - mountPath: /opt/app-root/src/config
101
127
  name: config-volume
@@ -5,11 +5,13 @@ metadata:
5
5
  labels:
6
6
  app: <%= projectName %>
7
7
  parameters:
8
+ <% if (!sandbox) { %>
8
9
  - name: INFRA_PROJECT
9
10
  description: Project used for build infrastructure.
10
11
  displayName: Infrastructure Project
11
12
  value: <%= ocInfraProject %>
12
13
  required: true
14
+ <% } %>
13
15
  - name: PROJECT
14
16
  description: Project to deploy into.
15
17
  displayName: Project
@@ -19,17 +21,21 @@ parameters:
19
21
  displayName: Application Name
20
22
  value: <%= projectName %>
21
23
  required: true
24
+ <% if (!sandbox) { %>
22
25
  - name: DEPLOY_TAG
23
26
  description: ImageStream tag to deploy.
24
27
  displayName: Deploy Tag
25
28
  value: latest
26
29
  required: true
30
+ <% } %>
27
31
  objects:
32
+ <% if (!sandbox) { %>
28
33
  - apiVersion: image.openshift.io/v1
29
34
  kind: ImageStream
30
35
  metadata:
31
36
  name: ${APP_NAME}
32
37
  namespace: ${INFRA_PROJECT}
38
+ <% } %>
33
39
  - apiVersion: v1
34
40
  kind: ConfigMap
35
41
  metadata:
@@ -45,6 +51,7 @@ objects:
45
51
  metadata:
46
52
  name: ${APP_NAME}
47
53
  namespace: ${PROJECT}
54
+ <% if (!sandbox) { %>
48
55
  annotations:
49
56
  image.openshift.io/triggers: |-
50
57
  [
@@ -58,6 +65,7 @@ objects:
58
65
  "paused": true
59
66
  }
60
67
  ]
68
+ <% } %>
61
69
  spec:
62
70
  replicas: 1
63
71
  selector:
@@ -78,21 +86,39 @@ objects:
78
86
  <% if (database === 'postgres') { %>
79
87
  initContainers:
80
88
  - name: ${APP_NAME}-migrate
89
+ <% if (sandbox) { %>
90
+ image: image-registry.openshift-image-registry.svc:5000/${PROJECT}/<%= projectName %>:sandbox
91
+ <% } else { %>
81
92
  image: image-registry.openshift-image-registry.svc:5000/${INFRA_PROJECT}/${APP_NAME}:${DEPLOY_TAG}
93
+ <% } %>
82
94
  command: ["npx", "prisma", "migrate", "deploy"]
83
95
  envFrom:
84
96
  - configMapRef:
85
97
  name: ${APP_NAME}
86
98
  env:
99
+ <% if (sandbox) { %>
100
+ - name: POSTGRES_PASSWORD
101
+ valueFrom:
102
+ secretKeyRef:
103
+ name: sandbox-postgres-creds
104
+ key: POSTGRESQL_ADMIN_PASSWORD
105
+ - name: DATABASE_URL
106
+ value: postgresql://postgres:$(POSTGRES_PASSWORD)@sandbox-postgres:5432/<%= projectName %>_sandbox
107
+ <% } else { %>
87
108
  - name: DATABASE_URL
88
109
  valueFrom:
89
110
  secretKeyRef:
90
111
  name: ${APP_NAME}-database
91
112
  key: DATABASE_URL
113
+ <% } %>
92
114
  <% } %>
93
115
  containers:
94
116
  - name: ${APP_NAME}
117
+ <% if (sandbox) { %>
118
+ image: image-registry.openshift-image-registry.svc:5000/${PROJECT}/<%= projectName %>:sandbox
119
+ <% } else { %>
95
120
  image: ${APP_NAME}:${DEPLOY_TAG}
121
+ <% } %>
96
122
  envFrom:
97
123
  - configMapRef:
98
124
  name: ${APP_NAME}
@@ -102,13 +128,32 @@ objects:
102
128
  - name: LOG_LEVEL
103
129
  value: info
104
130
  <% if (database === 'postgres') { %>
131
+ <% if (sandbox) { %>
132
+ - name: POSTGRES_PASSWORD
133
+ valueFrom:
134
+ secretKeyRef:
135
+ name: sandbox-postgres-creds
136
+ key: POSTGRESQL_ADMIN_PASSWORD
137
+ - name: DATABASE_URL
138
+ value: postgresql://postgres:$(POSTGRES_PASSWORD)@sandbox-postgres:5432/<%= projectName %>_sandbox
139
+ <% } else { %>
105
140
  # Set via: oc create secret generic ${APP_NAME}-database --from-literal=DATABASE_URL=<connection-string>
106
141
  - name: DATABASE_URL
107
142
  valueFrom:
108
143
  secretKeyRef:
109
144
  name: ${APP_NAME}-database
110
145
  key: DATABASE_URL
146
+ <% } %>
111
147
  <% } else if (database === 'mongo') { %>
148
+ <% if (sandbox) { %>
149
+ - name: MONGO_PASSWORD
150
+ valueFrom:
151
+ secretKeyRef:
152
+ name: sandbox-mongodb-creds
153
+ key: MONGODB_ADMIN_PASSWORD
154
+ - name: MONGODB_URI
155
+ value: mongodb://admin:$(MONGO_PASSWORD)@sandbox-mongodb:27017/<%= projectName %>_sandbox?authSource=admin
156
+ <% } else { %>
112
157
  # Set via: oc create secret generic ${APP_NAME}-database --from-literal=MONGODB_URI=<connection-string>
113
158
  - name: MONGODB_URI
114
159
  valueFrom:
@@ -116,7 +161,8 @@ objects:
116
161
  name: ${APP_NAME}-database
117
162
  key: MONGODB_URI
118
163
  <% } %>
119
- imagePullPolicy: IfNotPresent
164
+ <% } %>
165
+ imagePullPolicy: <%= sandbox ? 'Always' : 'IfNotPresent' %>
120
166
  ports:
121
167
  - containerPort: 3333
122
168
  name: http
@@ -128,6 +174,20 @@ objects:
128
174
  requests:
129
175
  cpu: 20m
130
176
  memory: 50Mi
177
+ readinessProbe:
178
+ httpGet:
179
+ path: /health
180
+ port: 3333
181
+ initialDelaySeconds: 10
182
+ periodSeconds: 10
183
+ failureThreshold: 3
184
+ livenessProbe:
185
+ httpGet:
186
+ path: /health
187
+ port: 3333
188
+ initialDelaySeconds: 30
189
+ periodSeconds: 30
190
+ failureThreshold: 3
131
191
  - apiVersion: v1
132
192
  kind: Service
133
193
  metadata:
@@ -10,6 +10,7 @@ export interface Schema {
10
10
  adsp?: AdspConfiguration;
11
11
  accessToken?: string;
12
12
  database?: DatabaseType;
13
+ sandbox?: boolean;
13
14
  }
14
15
 
15
16
  export interface NormalizedSchema extends Schema {
@@ -58,6 +58,10 @@
58
58
  "type": "string",
59
59
  "description": "Database type used by the service. When set, the deployment manifest references the appropriate Secret.",
60
60
  "enum": ["none", "postgres", "mongo"]
61
+ },
62
+ "sandbox": {
63
+ "type": "boolean",
64
+ "description": "Generate a sandbox deployment manifest (local image push, no ImageStream trigger)."
61
65
  }
62
66
  },
63
67
  "required": [
@@ -0,0 +1,104 @@
1
+ # Shared MongoDB instance for the sandbox namespace on GoA ARO OpenShift.
2
+ # Applied once per namespace — idempotent, safe to re-run. The PVC is never
3
+ # deleted on re-apply, so data persists across deployments.
4
+ #
5
+ # Multiple apps in the same namespace share this instance. Each app uses its
6
+ # own database (<appName>_sandbox); MongoDB creates it on first write.
7
+ #
8
+ # Credentials are stored in the sandbox-mongodb-creds Secret, created once
9
+ # per namespace by `nx run <app>:sandbox` on first use. Subsequent apps read
10
+ # from the same Secret so all apps share consistent credentials.
11
+ #
12
+ # StorageClass: azure-disk is required on GoA ARO.
13
+ ---
14
+ apiVersion: v1
15
+ kind: PersistentVolumeClaim
16
+ metadata:
17
+ name: sandbox-mongodb-data
18
+ spec:
19
+ storageClassName: azure-disk
20
+ accessModes:
21
+ - ReadWriteOnce
22
+ resources:
23
+ requests:
24
+ storage: 5Gi
25
+ ---
26
+ apiVersion: apps/v1
27
+ kind: Deployment
28
+ metadata:
29
+ name: sandbox-mongodb
30
+ labels:
31
+ app: sandbox-mongodb
32
+ spec:
33
+ replicas: 1
34
+ selector:
35
+ matchLabels:
36
+ app: sandbox-mongodb
37
+ strategy:
38
+ type: Recreate
39
+ template:
40
+ metadata:
41
+ labels:
42
+ app: sandbox-mongodb
43
+ spec:
44
+ containers:
45
+ - name: mongodb
46
+ image: quay.io/sclorg/mongodb-70-c9s:latest
47
+ ports:
48
+ - containerPort: 27017
49
+ protocol: TCP
50
+ env:
51
+ - name: MONGODB_ADMIN_PASSWORD
52
+ valueFrom:
53
+ secretKeyRef:
54
+ name: sandbox-mongodb-creds
55
+ key: MONGODB_ADMIN_PASSWORD
56
+ volumeMounts:
57
+ - name: data
58
+ mountPath: /var/lib/mongodb/data
59
+ readinessProbe:
60
+ exec:
61
+ command:
62
+ - mongosh
63
+ - --eval
64
+ - "db.adminCommand('ping')"
65
+ initialDelaySeconds: 10
66
+ periodSeconds: 10
67
+ timeoutSeconds: 5
68
+ failureThreshold: 3
69
+ livenessProbe:
70
+ exec:
71
+ command:
72
+ - mongosh
73
+ - --eval
74
+ - "db.adminCommand('ping')"
75
+ initialDelaySeconds: 30
76
+ periodSeconds: 20
77
+ timeoutSeconds: 5
78
+ failureThreshold: 3
79
+ resources:
80
+ requests:
81
+ cpu: "100m"
82
+ memory: "256Mi"
83
+ limits:
84
+ cpu: "500m"
85
+ memory: "512Mi"
86
+ volumes:
87
+ - name: data
88
+ persistentVolumeClaim:
89
+ claimName: sandbox-mongodb-data
90
+ ---
91
+ apiVersion: v1
92
+ kind: Service
93
+ metadata:
94
+ name: sandbox-mongodb
95
+ labels:
96
+ app: sandbox-mongodb
97
+ spec:
98
+ selector:
99
+ app: sandbox-mongodb
100
+ ports:
101
+ - name: mongodb
102
+ port: 27017
103
+ targetPort: 27017
104
+ protocol: TCP
@@ -0,0 +1,100 @@
1
+ # Shared Postgres instance for the sandbox namespace on GoA ARO OpenShift.
2
+ # Applied once per namespace — idempotent, safe to re-run. The PVC is never
3
+ # deleted on re-apply, so data persists across deployments.
4
+ #
5
+ # Multiple apps in the same namespace share this instance. Each app uses its
6
+ # own database (<appName>_sandbox) created automatically by Prisma migrate.
7
+ #
8
+ # Credentials are stored in the sandbox-postgres-creds Secret, created once
9
+ # per namespace by `nx run <app>:sandbox` on first use. Subsequent apps read
10
+ # from the same Secret so all apps share consistent credentials.
11
+ #
12
+ # StorageClass: azure-disk is required on GoA ARO.
13
+ # azure-file will NOT work: SMB mounts with root ownership and Postgres
14
+ # refuses to start on a data directory it does not own.
15
+ ---
16
+ apiVersion: v1
17
+ kind: PersistentVolumeClaim
18
+ metadata:
19
+ name: sandbox-postgres-data
20
+ spec:
21
+ storageClassName: azure-disk
22
+ accessModes:
23
+ - ReadWriteOnce
24
+ resources:
25
+ requests:
26
+ storage: 5Gi
27
+ ---
28
+ apiVersion: apps/v1
29
+ kind: Deployment
30
+ metadata:
31
+ name: sandbox-postgres
32
+ labels:
33
+ app: sandbox-postgres
34
+ spec:
35
+ replicas: 1
36
+ selector:
37
+ matchLabels:
38
+ app: sandbox-postgres
39
+ strategy:
40
+ type: Recreate
41
+ template:
42
+ metadata:
43
+ labels:
44
+ app: sandbox-postgres
45
+ spec:
46
+ containers:
47
+ - name: postgres
48
+ image: quay.io/sclorg/postgresql-16-c9s:latest
49
+ ports:
50
+ - containerPort: 5432
51
+ protocol: TCP
52
+ env:
53
+ - name: POSTGRESQL_ADMIN_PASSWORD
54
+ valueFrom:
55
+ secretKeyRef:
56
+ name: sandbox-postgres-creds
57
+ key: POSTGRESQL_ADMIN_PASSWORD
58
+ volumeMounts:
59
+ - name: data
60
+ mountPath: /var/lib/pgsql/data
61
+ readinessProbe:
62
+ exec:
63
+ command: ["pg_isready", "-U", "postgres"]
64
+ initialDelaySeconds: 5
65
+ periodSeconds: 10
66
+ timeoutSeconds: 3
67
+ failureThreshold: 3
68
+ livenessProbe:
69
+ exec:
70
+ command: ["pg_isready", "-U", "postgres"]
71
+ initialDelaySeconds: 15
72
+ periodSeconds: 20
73
+ timeoutSeconds: 5
74
+ failureThreshold: 3
75
+ resources:
76
+ requests:
77
+ cpu: "100m"
78
+ memory: "256Mi"
79
+ limits:
80
+ cpu: "500m"
81
+ memory: "512Mi"
82
+ volumes:
83
+ - name: data
84
+ persistentVolumeClaim:
85
+ claimName: sandbox-postgres-data
86
+ ---
87
+ apiVersion: v1
88
+ kind: Service
89
+ metadata:
90
+ name: sandbox-postgres
91
+ labels:
92
+ app: sandbox-postgres
93
+ spec:
94
+ selector:
95
+ app: sandbox-postgres
96
+ ports:
97
+ - name: postgres
98
+ port: 5432
99
+ targetPort: 5432
100
+ protocol: TCP
@@ -0,0 +1,3 @@
1
+ import { Tree } from '@nx/devkit';
2
+ import { Schema } from './schema';
3
+ export default function (host: Tree, options: Schema): Promise<void>;
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = default_1;
4
+ const tslib_1 = require("tslib");
5
+ const devkit_1 = require("@nx/devkit");
6
+ const path = require("path");
7
+ const adsp_1 = require("../../adsp");
8
+ const git_utils_1 = require("../../utils/git-utils");
9
+ function normalizeOptions(host, options) {
10
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
11
+ var _a;
12
+ const projectName = (0, devkit_1.names)(options.project).fileName;
13
+ const config = (0, devkit_1.readProjectConfiguration)(host, projectName);
14
+ let appType = options.appType;
15
+ if (!appType) {
16
+ switch (config.targets.build.executor) {
17
+ case '@nx/web:webpack':
18
+ case '@angular-devkit/build-angular:browser':
19
+ appType = 'frontend';
20
+ break;
21
+ case '@nx/node:build':
22
+ appType = 'node';
23
+ break;
24
+ case '@nx-dotnet/core:build':
25
+ appType = 'dotnet';
26
+ break;
27
+ case '@nx/webpack:webpack':
28
+ appType =
29
+ config.targets.build.options.target === 'node' ? 'node' : 'frontend';
30
+ break;
31
+ }
32
+ }
33
+ const adsp = yield (0, adsp_1.getAdspConfiguration)(host, Object.assign(Object.assign({}, options), { env: (_a = options.env) !== null && _a !== void 0 ? _a : 'dev' }));
34
+ return Object.assign(Object.assign({}, options), { appType,
35
+ adsp,
36
+ projectName });
37
+ });
38
+ }
39
+ function addManifestFiles(host, options) {
40
+ var _a;
41
+ const templateOptions = Object.assign(Object.assign(Object.assign({}, options), options.adsp), { sourceRepositoryUrl: (0, git_utils_1.getGitRemoteUrl)(), database: (_a = options.database) !== null && _a !== void 0 ? _a : 'none', sandbox: true, ocInfraProject: options.sandboxProject, tmpl: '' });
42
+ (0, devkit_1.generateFiles)(host, path.join(__dirname, `../deployment/${options.appType}-files`), `./.openshift/${options.projectName}`, templateOptions);
43
+ }
44
+ function addDatabaseFiles(host, options) {
45
+ if (!options.database || options.database === 'none')
46
+ return;
47
+ (0, devkit_1.generateFiles)(host, path.join(__dirname, 'database-files'), './.openshift/sandbox', { database: options.database, tmpl: '' });
48
+ }
49
+ function addSandboxTarget(host, options) {
50
+ const config = (0, devkit_1.readProjectConfiguration)(host, options.project);
51
+ const { projectName, sandboxProject, database } = options;
52
+ const commands = [];
53
+ if (database === 'postgres') {
54
+ commands.push(`oc get secret sandbox-postgres-creds -n ${sandboxProject} 2>/dev/null || ` +
55
+ `oc create secret generic sandbox-postgres-creds ` +
56
+ `--from-literal=POSTGRESQL_ADMIN_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=') ` +
57
+ `-n ${sandboxProject}`);
58
+ commands.push(`oc apply -f .openshift/sandbox/sandbox-postgres.yml -n ${sandboxProject}`);
59
+ }
60
+ else if (database === 'mongo') {
61
+ commands.push(`oc get secret sandbox-mongodb-creds -n ${sandboxProject} 2>/dev/null || ` +
62
+ `oc create secret generic sandbox-mongodb-creds ` +
63
+ `--from-literal=MONGODB_ADMIN_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=') ` +
64
+ `-n ${sandboxProject}`);
65
+ commands.push(`oc apply -f .openshift/sandbox/sandbox-mongodb.yml -n ${sandboxProject}`);
66
+ }
67
+ commands.push(`oc process -f .openshift/${projectName}/${projectName}.yml -p PROJECT=${sandboxProject} | oc apply -f -`);
68
+ commands.push([
69
+ `REGISTRY=$(oc registry info)`,
70
+ `CONTAINER_CLI=$(command -v podman || command -v docker)`,
71
+ `$CONTAINER_CLI login -u $(oc whoami) -p $(oc whoami -t) $REGISTRY`,
72
+ `$CONTAINER_CLI build -t $REGISTRY/${sandboxProject}/${projectName}:sandbox -f .openshift/${projectName}/Dockerfile .`,
73
+ `$CONTAINER_CLI push $REGISTRY/${sandboxProject}/${projectName}:sandbox`,
74
+ ].join(' && '));
75
+ commands.push(`oc rollout restart deployment/${projectName} -n ${sandboxProject}`);
76
+ commands.push(`oc rollout status deployment/${projectName} -n ${sandboxProject} --timeout=120s`);
77
+ config.targets = Object.assign(Object.assign({}, config.targets), { sandbox: {
78
+ executor: 'nx:run-commands',
79
+ options: {
80
+ commands,
81
+ sequential: true,
82
+ },
83
+ } });
84
+ (0, devkit_1.updateProjectConfiguration)(host, options.project, config);
85
+ }
86
+ function default_1(host, options) {
87
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
88
+ const normalizedOptions = yield normalizeOptions(host, options);
89
+ if (!normalizedOptions.appType) {
90
+ console.log('Cannot generate sandbox deployment for unknown project type.');
91
+ return;
92
+ }
93
+ addManifestFiles(host, normalizedOptions);
94
+ addDatabaseFiles(host, normalizedOptions);
95
+ addSandboxTarget(host, normalizedOptions);
96
+ yield (0, devkit_1.formatFiles)(host);
97
+ });
98
+ }
99
+ //# sourceMappingURL=sandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../../../../../packages/nx-oc/src/generators/sandbox/sandbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,133 @@
1
+ import {
2
+ addProjectConfiguration,
3
+ readProjectConfiguration,
4
+ } from '@nx/devkit';
5
+ import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
6
+ import * as utils from '../../adsp';
7
+ import { environments } from '../../adsp';
8
+ import generator from './sandbox';
9
+ import { Schema } from './schema';
10
+
11
+ jest.mock('../../adsp');
12
+ const utilsMock = utils as jest.Mocked<typeof utils>;
13
+ utilsMock.getAdspConfiguration.mockResolvedValue({
14
+ tenant: 'test',
15
+ tenantRealm: 'test',
16
+ accessServiceUrl: environments.test.accessServiceUrl,
17
+ directoryServiceUrl: environments.test.directoryServiceUrl,
18
+ });
19
+
20
+ describe('Sandbox Generator', () => {
21
+ const options: Schema = {
22
+ project: 'test',
23
+ sandboxProject: 'test-sandbox',
24
+ };
25
+
26
+ function addNodeProject(host) {
27
+ addProjectConfiguration(host, 'test', {
28
+ root: 'apps/test',
29
+ projectType: 'application',
30
+ targets: {
31
+ build: {
32
+ executor: '@nx/webpack:webpack',
33
+ options: { compiler: 'tsc', target: 'node' },
34
+ },
35
+ },
36
+ });
37
+ }
38
+
39
+ function addFrontendProject(host) {
40
+ addProjectConfiguration(host, 'test', {
41
+ root: 'apps/test',
42
+ projectType: 'application',
43
+ targets: {
44
+ build: {
45
+ executor: '@nx/webpack:webpack',
46
+ options: { compiler: 'babel' },
47
+ },
48
+ },
49
+ });
50
+ }
51
+
52
+ it('generates sandbox manifest for node app', async () => {
53
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
54
+ addNodeProject(host);
55
+
56
+ await generator(host, options);
57
+
58
+ expect(host.exists('.openshift/test/test.yml')).toBeTruthy();
59
+ const manifest = host.read('.openshift/test/test.yml').toString();
60
+ expect(manifest).toContain('imagePullPolicy: Always');
61
+ expect(manifest).not.toContain('ImageStream');
62
+ expect(manifest).not.toContain('DEPLOY_TAG');
63
+ expect(manifest).toContain('sandbox');
64
+ });
65
+
66
+ it('generates sandbox manifest for frontend app', async () => {
67
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
68
+ addFrontendProject(host);
69
+
70
+ await generator(host, options);
71
+
72
+ expect(host.exists('.openshift/test/test.yml')).toBeTruthy();
73
+ const manifest = host.read('.openshift/test/test.yml').toString();
74
+ expect(manifest).toContain('imagePullPolicy: Always');
75
+ expect(manifest).not.toContain('ImageStream');
76
+ });
77
+
78
+ it('adds sandbox nx target', async () => {
79
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
80
+ addNodeProject(host);
81
+
82
+ await generator(host, options);
83
+
84
+ const config = readProjectConfiguration(host, 'test');
85
+ expect(config.targets['sandbox']).toBeTruthy();
86
+ expect(config.targets['sandbox'].executor).toBe('nx:run-commands');
87
+ const cmds: string[] = config.targets['sandbox'].options.commands;
88
+ expect(cmds.some((c) => c.includes('oc rollout restart'))).toBeTruthy();
89
+ expect(cmds.some((c) => c.includes('oc rollout status'))).toBeTruthy();
90
+ expect(cmds.some((c) => c.includes('command -v podman'))).toBeTruthy();
91
+ });
92
+
93
+ it('generates shared postgres manifest with secret-backed DATABASE_URL', async () => {
94
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
95
+ addNodeProject(host);
96
+
97
+ await generator(host, { ...options, database: 'postgres' });
98
+
99
+ expect(host.exists('.openshift/sandbox/sandbox-postgres.yml')).toBeTruthy();
100
+
101
+ const dbManifest = host.read('.openshift/sandbox/sandbox-postgres.yml').toString();
102
+ expect(dbManifest).toContain('sandbox-postgres-creds');
103
+
104
+ const appManifest = host.read('.openshift/test/test.yml').toString();
105
+ expect(appManifest).toContain('sandbox-postgres-creds');
106
+ expect(appManifest).toContain('$(POSTGRES_PASSWORD)');
107
+
108
+ const config = readProjectConfiguration(host, 'test');
109
+ const cmds: string[] = config.targets['sandbox'].options.commands;
110
+ expect(cmds.some((c) => c.includes('sandbox-postgres-creds'))).toBeTruthy();
111
+ expect(cmds.some((c) => c.includes('sandbox-postgres.yml'))).toBeTruthy();
112
+ });
113
+
114
+ it('generates shared mongodb manifest with secret-backed MONGODB_URI', async () => {
115
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
116
+ addNodeProject(host);
117
+
118
+ await generator(host, { ...options, database: 'mongo' });
119
+
120
+ expect(host.exists('.openshift/sandbox/sandbox-mongodb.yml')).toBeTruthy();
121
+
122
+ const dbManifest = host.read('.openshift/sandbox/sandbox-mongodb.yml').toString();
123
+ expect(dbManifest).toContain('sandbox-mongodb-creds');
124
+
125
+ const appManifest = host.read('.openshift/test/test.yml').toString();
126
+ expect(appManifest).toContain('sandbox-mongodb-creds');
127
+ expect(appManifest).toContain('$(MONGO_PASSWORD)');
128
+
129
+ const config = readProjectConfiguration(host, 'test');
130
+ const cmds: string[] = config.targets['sandbox'].options.commands;
131
+ expect(cmds.some((c) => c.includes('sandbox-mongodb-creds'))).toBeTruthy();
132
+ });
133
+ });
@@ -0,0 +1,18 @@
1
+ import { AdspConfiguration } from '../../adsp';
2
+ import { ApplicationType, DatabaseType } from '../deployment/schema';
3
+
4
+ export interface Schema {
5
+ project: string;
6
+ appType?: ApplicationType;
7
+ sandboxProject: string;
8
+ database?: DatabaseType;
9
+ env?: string;
10
+ adsp?: AdspConfiguration;
11
+ accessToken?: string;
12
+ }
13
+
14
+ export interface NormalizedSchema extends Schema {
15
+ projectName: string;
16
+ appType: ApplicationType;
17
+ adsp: AdspConfiguration;
18
+ }
@@ -0,0 +1,50 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "id": "NxOcSandbox",
4
+ "title": "OpenShift Sandbox Deployment",
5
+ "type": "object",
6
+ "properties": {
7
+ "project": {
8
+ "type": "string",
9
+ "description": "Project to add sandbox deployment for.",
10
+ "$default": {
11
+ "$source": "argv",
12
+ "index": 0
13
+ },
14
+ "x-prompt": "Which project to add sandbox deployment for?"
15
+ },
16
+ "sandboxProject": {
17
+ "type": "string",
18
+ "description": "OpenShift namespace to deploy the sandbox into.",
19
+ "alias": "s",
20
+ "x-prompt": "Which OpenShift namespace should be used for the sandbox?"
21
+ },
22
+ "appType": {
23
+ "type": "string",
24
+ "description": "Type of application.",
25
+ "alias": "t",
26
+ "x-prompt": {
27
+ "message": "What type of application is the project?",
28
+ "type": "list",
29
+ "items": ["frontend", "dotnet", "node"]
30
+ }
31
+ },
32
+ "database": {
33
+ "type": "string",
34
+ "description": "Database type. A shared containerized instance will be deployed to the sandbox namespace.",
35
+ "enum": ["none", "postgres", "mongo"]
36
+ },
37
+ "env": {
38
+ "type": "string",
39
+ "description": "ADSP environment to target.",
40
+ "default": "dev"
41
+ },
42
+ "accessToken": {
43
+ "type": "string",
44
+ "description": "Access token for retrieving configuration from ADSP APIs.",
45
+ "alias": "at"
46
+ }
47
+ },
48
+ "required": ["project", "sandboxProject"],
49
+ "additionalProperties": false
50
+ }