@codiac.io/codiac-cli 1.2.167 → 1.2.169

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.
Files changed (522) hide show
  1. package/README.md +3326 -45
  2. package/bin/dev +16 -16
  3. package/bin/dev.cmd +2 -2
  4. package/bin/run +3 -3
  5. package/bin/run.cmd +3 -3
  6. package/codiac.json +9 -9
  7. package/lib/api-command-base.d.ts +0 -0
  8. package/lib/api-command-base.js +52 -0
  9. package/lib/api-command-base.js.map +1 -0
  10. package/lib/apis/codiac-api/common/api-client-base.d.ts +165 -165
  11. package/lib/apis/codiac-api/common/api-client-base.js +547 -547
  12. package/lib/apis/codiac-api/common/api-user-creds.d.ts +7 -7
  13. package/lib/apis/codiac-api/common/api-user-creds.js +18 -18
  14. package/lib/apis/codiac-api/common/config-loader.d.ts +6 -6
  15. package/lib/apis/codiac-api/common/config-loader.js +18 -18
  16. package/lib/apis/codiac-api/common/endpoint-spec.d.ts +17 -17
  17. package/lib/apis/codiac-api/common/endpoint-spec.js +27 -27
  18. package/lib/apis/codiac-api/common/security/api-auth-methods-legacy.d.ts +87 -87
  19. package/lib/apis/codiac-api/common/security/api-auth-methods-legacy.js +367 -367
  20. package/lib/apis/codiac-api/common/security/auth-constants.d.ts +15 -15
  21. package/lib/apis/codiac-api/common/security/auth-constants.js +21 -21
  22. package/lib/apis/codiac-api/common/security/i-auth-client.d.ts +44 -44
  23. package/lib/apis/codiac-api/common/security/i-auth-client.js +2 -2
  24. package/lib/apis/codiac-api/common/security/token-holder.d.ts +13 -13
  25. package/lib/apis/codiac-api/common/security/token-holder.js +17 -17
  26. package/lib/apis/codiac-api/common/utils.d.ts +23 -23
  27. package/lib/apis/codiac-api/common/utils.js +82 -82
  28. package/lib/apis/codiac-api/contracts/index.d.ts +1 -1
  29. package/lib/apis/codiac-api/contracts/index.js +4 -4
  30. package/lib/apis/codiac-api/gen/client-config.d.ts +10 -10
  31. package/lib/apis/codiac-api/gen/client-config.js +28 -28
  32. package/lib/apis/codiac-api/gen/client.d.ts +1663 -1663
  33. package/lib/apis/codiac-api/gen/client.js +15629 -15629
  34. package/lib/apis/codiac-api/gen/contracts.d.ts +2722 -2722
  35. package/lib/apis/codiac-api/gen/contracts.js +402 -402
  36. package/lib/apis/codiac-api/index.d.ts +3 -3
  37. package/lib/apis/codiac-api/index.js +8 -8
  38. package/lib/apis/codiac-relay/common/api-client-base.d.ts +165 -165
  39. package/lib/apis/codiac-relay/common/api-client-base.js +547 -547
  40. package/lib/apis/codiac-relay/common/api-user-creds.d.ts +7 -7
  41. package/lib/apis/codiac-relay/common/api-user-creds.js +18 -18
  42. package/lib/apis/codiac-relay/common/config-loader.d.ts +6 -6
  43. package/lib/apis/codiac-relay/common/config-loader.js +18 -18
  44. package/lib/apis/codiac-relay/common/endpoint-spec.d.ts +17 -17
  45. package/lib/apis/codiac-relay/common/endpoint-spec.js +27 -27
  46. package/lib/apis/codiac-relay/common/security/api-auth-methods-legacy.d.ts +87 -87
  47. package/lib/apis/codiac-relay/common/security/api-auth-methods-legacy.js +367 -367
  48. package/lib/apis/codiac-relay/common/security/auth-constants.d.ts +15 -15
  49. package/lib/apis/codiac-relay/common/security/auth-constants.js +21 -21
  50. package/lib/apis/codiac-relay/common/security/i-auth-client.d.ts +44 -44
  51. package/lib/apis/codiac-relay/common/security/i-auth-client.js +2 -2
  52. package/lib/apis/codiac-relay/common/security/token-holder.d.ts +13 -13
  53. package/lib/apis/codiac-relay/common/security/token-holder.js +17 -17
  54. package/lib/apis/codiac-relay/common/utils.d.ts +23 -23
  55. package/lib/apis/codiac-relay/common/utils.js +82 -82
  56. package/lib/apis/codiac-relay/contracts/index.d.ts +1 -1
  57. package/lib/apis/codiac-relay/contracts/index.js +4 -4
  58. package/lib/apis/codiac-relay/gen/client-config.d.ts +10 -10
  59. package/lib/apis/codiac-relay/gen/client-config.js +28 -28
  60. package/lib/apis/codiac-relay/gen/client.d.ts +244 -244
  61. package/lib/apis/codiac-relay/gen/client.js +1862 -1862
  62. package/lib/apis/codiac-relay/gen/contracts.d.ts +3111 -3111
  63. package/lib/apis/codiac-relay/gen/contracts.js +434 -434
  64. package/lib/apis/codiac-relay/index.d.ts +3 -3
  65. package/lib/apis/codiac-relay/index.js +8 -8
  66. package/lib/azure-rest-client.d.ts +6 -0
  67. package/lib/azure-rest-client.js +36 -0
  68. package/lib/azure-rest-client.js.map +1 -0
  69. package/lib/cli-common/ImagesList.js +66 -66
  70. package/lib/cli-common/argument-manager.d.ts +28 -28
  71. package/lib/cli-common/argument-manager.js +194 -194
  72. package/lib/cli-common/built-in-cli-user-input.d.ts +18 -18
  73. package/lib/cli-common/built-in-cli-user-input.js +309 -309
  74. package/lib/cli-common/cli-interfaces.js +6 -6
  75. package/lib/cli-common/command-base.d.ts +72 -72
  76. package/lib/cli-common/command-base.js +181 -181
  77. package/lib/cli-common/entities/index.d.ts +1 -1
  78. package/lib/cli-common/entities/index.js +4 -4
  79. package/lib/cli-common/entities/prompt-choice.d.ts +7 -7
  80. package/lib/cli-common/entities/prompt-choice.js +2 -2
  81. package/lib/cli-common/file-selector.d.ts +48 -48
  82. package/lib/cli-common/file-selector.js +186 -186
  83. package/lib/cli-common/i-user-input-provider.js +18 -18
  84. package/lib/cli-common/index.d.ts +4 -4
  85. package/lib/cli-common/index.js +10 -10
  86. package/lib/cli-common/mock-ui.d.ts +27 -27
  87. package/lib/cli-common/mock-ui.js +82 -82
  88. package/lib/cli-common/prompt-select-fuzzy.d.ts +19 -19
  89. package/lib/cli-common/prompt-select-fuzzy.js +118 -118
  90. package/lib/cli-common/tenant-contextualizer.js +435 -435
  91. package/lib/cli-common/test/tenant-contextualizer.spec.js +142 -142
  92. package/lib/cli-entities/output-format-enum.d.ts +7 -7
  93. package/lib/cli-entities/output-format-enum.js +11 -11
  94. package/lib/cli-entities/prompt-choice.js +5 -5
  95. package/lib/codiac-constants.d.ts +35 -35
  96. package/lib/codiac-constants.js +40 -40
  97. package/lib/codiac-entities/asset-binding.d.ts +12 -12
  98. package/lib/codiac-entities/asset-binding.js +17 -17
  99. package/lib/codiac-entities/azure-container-registry.d.ts +4 -4
  100. package/lib/codiac-entities/azure-container-registry.js +2 -2
  101. package/lib/codiac-entities/azure-service-principal.d.ts +23 -23
  102. package/lib/codiac-entities/azure-service-principal.js +23 -23
  103. package/lib/codiac-entities/cloud-account-ref.d.ts +28 -28
  104. package/lib/codiac-entities/cloud-account-ref.js +36 -36
  105. package/lib/codiac-entities/deployment-temp.js +132 -132
  106. package/lib/codiac-entities/i-cloud-account-ref.d.ts +5 -5
  107. package/lib/codiac-entities/i-cloud-account-ref.js +2 -2
  108. package/lib/command-base-enterprise.d.ts +121 -121
  109. package/lib/command-base-enterprise.js +523 -523
  110. package/lib/command-base-tenantless.d.ts +44 -44
  111. package/lib/command-base-tenantless.js +172 -172
  112. package/lib/commands/asset/create.d.ts +42 -42
  113. package/lib/commands/asset/create.js +466 -466
  114. package/lib/commands/asset/destroy.d.ts +20 -20
  115. package/lib/commands/asset/destroy.js +128 -128
  116. package/lib/commands/asset/helm.d.ts +23 -23
  117. package/lib/commands/asset/helm.js +152 -152
  118. package/lib/commands/asset/list.d.ts +28 -28
  119. package/lib/commands/asset/list.js +171 -171
  120. package/lib/commands/asset/probe/create.d.ts +38 -38
  121. package/lib/commands/asset/probe/create.js +186 -186
  122. package/lib/commands/asset/recycle.d.ts +23 -23
  123. package/lib/commands/asset/recycle.js +174 -174
  124. package/lib/commands/asset/view.d.ts +188 -188
  125. package/lib/commands/asset/view.js +1364 -1364
  126. package/lib/commands/asset/volume/create.d.ts +23 -23
  127. package/lib/commands/asset/volume/create.js +175 -175
  128. package/lib/commands/asset/volume/delete.d.ts +19 -19
  129. package/lib/commands/asset/volume/delete.js +111 -111
  130. package/lib/commands/asset/volume/list.d.ts +19 -19
  131. package/lib/commands/asset/volume/list.js +69 -69
  132. package/lib/commands/branch/current.d.ts +10 -10
  133. package/lib/commands/branch/current.js +33 -33
  134. package/lib/commands/branch/list.d.ts +15 -15
  135. package/lib/commands/branch/list.js +55 -55
  136. package/lib/commands/branch.d.ts +12 -12
  137. package/lib/commands/branch.js +41 -41
  138. package/lib/commands/build.d.ts +37 -37
  139. package/lib/commands/build.js +118 -118
  140. package/lib/commands/cabinet/create.d.ts +21 -21
  141. package/lib/commands/cabinet/create.js +107 -107
  142. package/lib/commands/cabinet/list.d.ts +23 -23
  143. package/lib/commands/cabinet/list.js +133 -133
  144. package/lib/commands/cabinet/obliterate.d.ts +20 -20
  145. package/lib/commands/cabinet/obliterate.js +82 -82
  146. package/lib/commands/cli.d.ts +10 -10
  147. package/lib/commands/cli.js +99 -99
  148. package/lib/commands/commit.d.ts +11 -11
  149. package/lib/commands/commit.js +39 -39
  150. package/lib/commands/config/add.d.ts +78 -78
  151. package/lib/commands/config/add.js +559 -559
  152. package/lib/commands/config/delete.d.ts +18 -18
  153. package/lib/commands/config/delete.js +118 -118
  154. package/lib/commands/config/deploy.d.ts +22 -22
  155. package/lib/commands/config/deploy.js +124 -124
  156. package/lib/commands/config/import.d.ts +27 -27
  157. package/lib/commands/config/import.js +195 -195
  158. package/lib/commands/config/view.d.ts +25 -25
  159. package/lib/commands/config/view.js +120 -120
  160. package/lib/commands/csp/login.d.ts +18 -18
  161. package/lib/commands/csp/login.js +108 -108
  162. package/lib/commands/csp/logout.d.ts +15 -15
  163. package/lib/commands/csp/logout.js +73 -73
  164. package/lib/commands/dep/create.d.ts +13 -13
  165. package/lib/commands/dep/create.js +40 -40
  166. package/lib/commands/dep/install.d.ts +9 -9
  167. package/lib/commands/dep/install.js +29 -29
  168. package/lib/commands/dep/list.d.ts +55 -55
  169. package/lib/commands/dep/list.js +97 -97
  170. package/lib/commands/dep/remove.d.ts +12 -12
  171. package/lib/commands/dep/remove.js +61 -61
  172. package/lib/commands/dep/source.d.ts +13 -13
  173. package/lib/commands/dep/source.js +82 -82
  174. package/lib/commands/dep/syncup.d.ts +11 -11
  175. package/lib/commands/dep/syncup.js +53 -53
  176. package/lib/commands/dep/unsource.d.ts +14 -14
  177. package/lib/commands/dep/unsource.js +67 -67
  178. package/lib/commands/dep/upgrade.d.ts +44 -44
  179. package/lib/commands/dep/upgrade.js +243 -243
  180. package/lib/commands/dep.d.ts +12 -12
  181. package/lib/commands/dep.js +50 -50
  182. package/lib/commands/deploy.d.ts +38 -38
  183. package/lib/commands/deploy.js +382 -382
  184. package/lib/commands/enterprise/create.d.ts +20 -20
  185. package/lib/commands/enterprise/create.js +97 -97
  186. package/lib/commands/enterprise/list.d.ts +14 -14
  187. package/lib/commands/enterprise/list.js +83 -83
  188. package/lib/commands/env/add.d.ts +22 -22
  189. package/lib/commands/env/add.js +199 -199
  190. package/lib/commands/environment/create.d.ts +19 -19
  191. package/lib/commands/environment/create.js +88 -88
  192. package/lib/commands/environment/list.d.ts +25 -25
  193. package/lib/commands/environment/list.js +157 -157
  194. package/lib/commands/filestore/capture.d.ts +31 -31
  195. package/lib/commands/filestore/capture.js +341 -341
  196. package/lib/commands/host/map.d.ts +33 -33
  197. package/lib/commands/host/map.js +346 -346
  198. package/lib/commands/identity/delete.d.ts +15 -15
  199. package/lib/commands/identity/delete.js +82 -82
  200. package/lib/commands/identity/list.d.ts +11 -11
  201. package/lib/commands/identity/list.js +42 -42
  202. package/lib/commands/identity.d.ts +22 -22
  203. package/lib/commands/identity.js +76 -76
  204. package/lib/commands/imageRegistry/capture.d.ts +27 -27
  205. package/lib/commands/imageRegistry/capture.js +159 -159
  206. package/lib/commands/imageRegistry/forget.d.ts +23 -23
  207. package/lib/commands/imageRegistry/forget.js +160 -160
  208. package/lib/commands/imageRegistry/pullSecret/set.d.ts +27 -27
  209. package/lib/commands/imageRegistry/pullSecret/set.js +299 -299
  210. package/lib/commands/imageRegistry/pullSecret/unset.d.ts +24 -24
  211. package/lib/commands/imageRegistry/pullSecret/unset.js +242 -242
  212. package/lib/commands/images/add.d.ts +25 -25
  213. package/lib/commands/images/add.js +75 -75
  214. package/lib/commands/images/list.d.ts +14 -14
  215. package/lib/commands/images/list.js +71 -71
  216. package/lib/commands/images/patch.d.ts +14 -14
  217. package/lib/commands/images/patch.js +92 -92
  218. package/lib/commands/images/remove.d.ts +12 -12
  219. package/lib/commands/images/remove.js +37 -37
  220. package/lib/commands/images/version.d.ts +16 -16
  221. package/lib/commands/images/version.js +64 -64
  222. package/lib/commands/init.d.ts +17 -17
  223. package/lib/commands/init.js +130 -130
  224. package/lib/commands/kit/create.d.ts +25 -25
  225. package/lib/commands/kit/create.js +141 -141
  226. package/lib/commands/login.d.ts +22 -22
  227. package/lib/commands/login.js +92 -92
  228. package/lib/commands/logout.d.ts +8 -8
  229. package/lib/commands/logout.js +36 -36
  230. package/lib/commands/merge.d.ts +12 -12
  231. package/lib/commands/merge.js +42 -42
  232. package/lib/commands/noc/cluster/create.d.ts +28 -28
  233. package/lib/commands/noc/cluster/create.js +132 -132
  234. package/lib/commands/noc/cluster/deinit.d.ts +17 -17
  235. package/lib/commands/noc/cluster/deinit.js +116 -116
  236. package/lib/commands/noc/cluster/destroy.d.ts +20 -20
  237. package/lib/commands/noc/cluster/destroy.js +137 -137
  238. package/lib/commands/noc/cluster/forget.d.ts +16 -16
  239. package/lib/commands/noc/cluster/forget.js +136 -136
  240. package/lib/commands/noc/cluster/grant.d.ts +24 -24
  241. package/lib/commands/noc/cluster/grant.js +159 -159
  242. package/lib/commands/noc/cluster/init.d.ts +17 -17
  243. package/lib/commands/noc/cluster/init.js +116 -116
  244. package/lib/commands/noc/cluster/list.d.ts +21 -21
  245. package/lib/commands/noc/cluster/list.js +83 -83
  246. package/lib/commands/noc/cluster/recreate.d.ts +28 -28
  247. package/lib/commands/noc/cluster/recreate.js +185 -185
  248. package/lib/commands/pkg/add.d.ts +15 -15
  249. package/lib/commands/pkg/add.js +42 -42
  250. package/lib/commands/pkg/list.d.ts +9 -9
  251. package/lib/commands/pkg/list.js +32 -32
  252. package/lib/commands/pkg/patch.d.ts +13 -13
  253. package/lib/commands/pkg/patch.js +78 -78
  254. package/lib/commands/pkg/remove.d.ts +12 -12
  255. package/lib/commands/pkg/remove.js +69 -69
  256. package/lib/commands/portal.d.ts +11 -11
  257. package/lib/commands/portal.js +81 -81
  258. package/lib/commands/publish.d.ts +21 -21
  259. package/lib/commands/publish.js +51 -51
  260. package/lib/commands/pull.d.ts +13 -13
  261. package/lib/commands/pull.js +29 -29
  262. package/lib/commands/push.d.ts +13 -13
  263. package/lib/commands/push.js +29 -29
  264. package/lib/commands/run.d.ts +35 -35
  265. package/lib/commands/run.js +193 -193
  266. package/lib/commands/secretStore/capture.d.ts +27 -27
  267. package/lib/commands/secretStore/capture.js +174 -174
  268. package/lib/commands/secretStore/forget.d.ts +20 -20
  269. package/lib/commands/secretStore/forget.js +146 -146
  270. package/lib/commands/stage.d.ts +13 -13
  271. package/lib/commands/stage.js +64 -64
  272. package/lib/commands/stash.d.ts +13 -13
  273. package/lib/commands/stash.js +30 -30
  274. package/lib/commands/status.d.ts +12 -12
  275. package/lib/commands/status.js +48 -48
  276. package/lib/commands/stop.d.ts +10 -10
  277. package/lib/commands/stop.js +51 -51
  278. package/lib/commands/switch.d.ts +11 -11
  279. package/lib/commands/switch.js +41 -41
  280. package/lib/commands/sync.d.ts +14 -14
  281. package/lib/commands/sync.js +20 -20
  282. package/lib/commands/tenant/create.d.ts +27 -27
  283. package/lib/commands/tenant/create.js +119 -119
  284. package/lib/commands/tenant/switch.d.ts +24 -24
  285. package/lib/commands/tenant/switch.js +108 -108
  286. package/lib/commands/unstage.d.ts +12 -12
  287. package/lib/commands/unstage.js +57 -57
  288. package/lib/commands/view/dashboard.d.ts +17 -0
  289. package/lib/commands/view/dashboard.js +88 -0
  290. package/lib/commands/view/dashboard.js.map +1 -0
  291. package/lib/commands/view/pods.d.ts +14 -0
  292. package/lib/commands/view/pods.js +88 -0
  293. package/lib/commands/view/pods.js.map +1 -0
  294. package/lib/commands/whereami.d.ts +15 -15
  295. package/lib/commands/whereami.js +122 -122
  296. package/lib/commands/whoami.d.ts +8 -8
  297. package/lib/commands/whoami.js +39 -39
  298. package/lib/deployment.d.ts +2 -0
  299. package/lib/deployment.js +7 -0
  300. package/lib/deployment.js.map +1 -0
  301. package/lib/errors/NoMembershipError.d.ts +8 -8
  302. package/lib/errors/NoMembershipError.js +14 -14
  303. package/lib/index.d.ts +1 -1
  304. package/lib/index.js +16 -16
  305. package/lib/k8s-command-base.d.ts +60 -0
  306. package/lib/k8s-command-base.js +204 -0
  307. package/lib/k8s-command-base.js.map +1 -0
  308. package/lib/log-update-wrapper.d.ts +24 -24
  309. package/lib/log-update-wrapper.js +28 -28
  310. package/lib/log4js-logger.d.ts +26 -26
  311. package/lib/log4js-logger.js +137 -137
  312. package/lib/ops/INTERFACES_CLI.d.ts +3 -3
  313. package/lib/ops/INTERFACES_CLI.js +7 -7
  314. package/lib/ops/LocalOps.d.ts +444 -444
  315. package/lib/ops/LocalOps.js +3183 -3183
  316. package/lib/ops/azure-container-registry-client/azure-container-registry-client.js +147 -147
  317. package/lib/ops/cli-path-walker.js +54 -54
  318. package/lib/ops/codiac-entities/dependency.d.ts +5 -5
  319. package/lib/ops/codiac-entities/dependency.js +10 -10
  320. package/lib/ops/codiac-entities/index.d.ts +1 -1
  321. package/lib/ops/codiac-entities/index.js +4 -4
  322. package/lib/ops/composite-image-registry-client.js +73 -73
  323. package/lib/ops/data/cli-context-repo.d.ts +61 -61
  324. package/lib/ops/data/cli-context-repo.js +269 -269
  325. package/lib/ops/data/index.d.ts +2 -2
  326. package/lib/ops/data/index.js +5 -5
  327. package/lib/ops/data/npm-config-repo.d.ts +13 -13
  328. package/lib/ops/data/npm-config-repo.js +64 -64
  329. package/lib/ops/docker-config.js +130 -130
  330. package/lib/ops/docker-constants.js +21 -21
  331. package/lib/ops/docker-credentials-store.js +237 -237
  332. package/lib/ops/docker-registry-api-client/docker-registry-api-client.js +288 -288
  333. package/lib/ops/docker-registry-api-client/entities/blob-sum.d.ts +7 -7
  334. package/lib/ops/docker-registry-api-client/entities/blob-sum.js +12 -12
  335. package/lib/ops/docker-registry-api-client/entities/docker-access-actions-enum.d.ts +5 -5
  336. package/lib/ops/docker-registry-api-client/entities/docker-access-actions-enum.js +9 -9
  337. package/lib/ops/docker-registry-api-client/entities/docker-auth-token-criteria.d.ts +30 -30
  338. package/lib/ops/docker-registry-api-client/entities/docker-auth-token-criteria.js +35 -35
  339. package/lib/ops/docker-registry-api-client/entities/i-docker-error-response.d.ts +55 -55
  340. package/lib/ops/docker-registry-api-client/entities/i-docker-error-response.js +51 -51
  341. package/lib/ops/docker-registry-api-client/entities/i-docker-list-response.d.ts +7 -7
  342. package/lib/ops/docker-registry-api-client/entities/i-docker-list-response.js +2 -2
  343. package/lib/ops/docker-registry-api-client/entities/image-repository.d.ts +31 -31
  344. package/lib/ops/docker-registry-api-client/entities/image-repository.js +29 -29
  345. package/lib/ops/docker-registry-api-client/entities/image-tag-criteria.d.ts +8 -8
  346. package/lib/ops/docker-registry-api-client/entities/image-tag-criteria.js +13 -13
  347. package/lib/ops/docker-registry-api-client/entities/image-tag-list.d.ts +7 -7
  348. package/lib/ops/docker-registry-api-client/entities/image-tag-list.js +12 -12
  349. package/lib/ops/docker-registry-api-client/entities/manifest-criteria.d.ts +9 -9
  350. package/lib/ops/docker-registry-api-client/entities/manifest-criteria.js +14 -14
  351. package/lib/ops/docker-registry-api-client/entities/manifest.d.ts +15 -15
  352. package/lib/ops/docker-registry-api-client/entities/manifest.js +20 -20
  353. package/lib/ops/docker-registry-api-client/entities/repository-criteria.d.ts +16 -16
  354. package/lib/ops/docker-registry-api-client/entities/repository-criteria.js +23 -23
  355. package/lib/ops/docker-registry-api-client/entities/token-response.d.ts +15 -15
  356. package/lib/ops/docker-registry-api-client/entities/token-response.js +14 -14
  357. package/lib/ops/docker-registry-api-client/entities/token.d.ts +17 -17
  358. package/lib/ops/docker-registry-api-client/entities/token.js +21 -21
  359. package/lib/ops/docker-registry-api-client/entities/version-check-criteria.d.ts +4 -4
  360. package/lib/ops/docker-registry-api-client/entities/version-check-criteria.js +9 -9
  361. package/lib/ops/dx-constants.d.ts +26 -26
  362. package/lib/ops/dx-constants.js +42 -42
  363. package/lib/ops/entities/ImageBuildContext.d.ts +12 -12
  364. package/lib/ops/entities/ImageBuildContext.js +18 -18
  365. package/lib/ops/entities/PipelineContext.d.ts +21 -21
  366. package/lib/ops/entities/PipelineContext.js +22 -22
  367. package/lib/ops/entities/TenantContext.d.ts +10 -10
  368. package/lib/ops/entities/TenantContext.js +15 -15
  369. package/lib/ops/entities/ThaulConfig.js +29 -29
  370. package/lib/ops/entities/azure-service-principal.d.ts +23 -23
  371. package/lib/ops/entities/azure-service-principal.js +23 -23
  372. package/lib/ops/entities/better-logger.js +1 -1
  373. package/lib/ops/entities/branch.d.ts +13 -13
  374. package/lib/ops/entities/branch.js +15 -15
  375. package/lib/ops/entities/cli-config.d.ts +48 -48
  376. package/lib/ops/entities/cli-config.js +60 -60
  377. package/lib/ops/entities/docker-image.d.ts +60 -60
  378. package/lib/ops/entities/docker-image.js +2 -2
  379. package/lib/ops/entities/helm-spec.d.ts +15 -15
  380. package/lib/ops/entities/helm-spec.js +22 -22
  381. package/lib/ops/entities/index.d.ts +4 -4
  382. package/lib/ops/entities/index.js +11 -11
  383. package/lib/ops/entities/operation-meta.d.ts +8 -8
  384. package/lib/ops/entities/operation-meta.js +18 -18
  385. package/lib/ops/entities/scaffolding.d.ts +19 -19
  386. package/lib/ops/entities/scaffolding.js +20 -20
  387. package/lib/ops/extensions/azart-identity-adapter.d.ts +19 -19
  388. package/lib/ops/extensions/azart-identity-adapter.js +96 -96
  389. package/lib/ops/extensions/npm-identity-adapter-base.d.ts +13 -13
  390. package/lib/ops/extensions/npm-identity-adapter-base.js +2 -2
  391. package/lib/ops/extensions/npmjs-identity-adapter.d.ts +13 -13
  392. package/lib/ops/extensions/npmjs-identity-adapter.js +63 -63
  393. package/lib/ops/git-ops.d.ts +8 -8
  394. package/lib/ops/git-ops.js +13 -13
  395. package/lib/ops/i-client-for-image-registry.js +16 -16
  396. package/lib/ops/i-identity-handler.d.ts +33 -33
  397. package/lib/ops/i-identity-handler.js +164 -164
  398. package/lib/ops/i-output-styler.js +16 -16
  399. package/lib/ops/index.d.ts +12 -12
  400. package/lib/ops/index.js +14 -14
  401. package/lib/ops/json-utils.js +58 -58
  402. package/lib/ops/no-style-output-styler.js +29 -29
  403. package/lib/ops/oauth2-client.ts/oauth2-client.d.ts +23 -23
  404. package/lib/ops/oauth2-client.ts/oauth2-client.js +63 -63
  405. package/lib/ops/project-initializer.d.ts +36 -36
  406. package/lib/ops/project-initializer.js +218 -218
  407. package/lib/ops/scaffolding/base-scaffolding.d.ts +7 -7
  408. package/lib/ops/scaffolding/base-scaffolding.js +20 -20
  409. package/lib/ops/scaffolding/codiac-api-scaffolding.d.ts +7 -7
  410. package/lib/ops/scaffolding/codiac-api-scaffolding.js +63 -63
  411. package/lib/ops/scaffolding/typescript-scaffolding.d.ts +15 -15
  412. package/lib/ops/scaffolding/typescript-scaffolding.js +162 -162
  413. package/lib/ops/test/mock-ui.d.ts +26 -26
  414. package/lib/ops/test/mock-ui.js +87 -87
  415. package/lib/ops/test/test-extensions.d.ts +13 -13
  416. package/lib/ops/test/test-extensions.js +70 -70
  417. package/lib/ops/test/when-a-recursive-file-search-is-run.spec.d.ts +2 -2
  418. package/lib/ops/test/when-a-recursive-file-search-is-run.spec.js +54 -54
  419. package/lib/ops/test/when-git-branchline-is-attempted.spec.d.ts +2 -2
  420. package/lib/ops/test/when-git-branchline-is-attempted.spec.js +37 -37
  421. package/lib/ops/test/when-versions-are-parsed.spec.d.ts +2 -2
  422. package/lib/ops/test/when-versions-are-parsed.spec.js +59 -59
  423. package/lib/ops/throwing-user-input-provider.js +36 -36
  424. package/lib/prettify.d.ts +7 -7
  425. package/lib/prettify.js +23 -23
  426. package/lib/read-stdin.d.ts +2 -2
  427. package/lib/read-stdin.js +28 -28
  428. package/lib/relay/contracts/contracts.d.ts +207 -207
  429. package/lib/relay/contracts/contracts.js +229 -229
  430. package/lib/relay/data/aws-k8s-versions.d.ts +6 -0
  431. package/lib/relay/data/aws-k8s-versions.js +16 -0
  432. package/lib/relay/data/aws-k8s-versions.js.map +1 -0
  433. package/lib/relay/data/aws-node-types.d.ts +37 -0
  434. package/lib/relay/data/aws-node-types.js +4246 -0
  435. package/lib/relay/data/aws-node-types.js.map +1 -0
  436. package/lib/relay/data/aws-regions.d.ts +6 -0
  437. package/lib/relay/data/aws-regions.js +34 -0
  438. package/lib/relay/data/aws-regions.js.map +1 -0
  439. package/lib/relay/extended-relay-client.d.ts +27 -27
  440. package/lib/relay/extended-relay-client.js +27 -27
  441. package/lib/relay/relay-container.d.ts +41 -41
  442. package/lib/relay/relay-container.js +297 -297
  443. package/lib/relay/wsclient/relay-socket-listener.d.ts +68 -68
  444. package/lib/relay/wsclient/relay-socket-listener.js +164 -164
  445. package/lib/relay/wsclient/relay-websocket-client.d.ts +33 -33
  446. package/lib/relay/wsclient/relay-websocket-client.js +178 -178
  447. package/lib/relay/wsclient/rx-websocket-subject.d.ts +25 -25
  448. package/lib/relay/wsclient/rx-websocket-subject.js +133 -133
  449. package/lib/relay/wsclient/socket-contracts.d.ts +22 -22
  450. package/lib/relay/wsclient/socket-contracts.js +2 -2
  451. package/lib/standard-probes.d.ts +5 -5
  452. package/lib/standard-probes.js +21 -21
  453. package/lib/uilogic/build-configurator.d.ts +21 -21
  454. package/lib/uilogic/build-configurator.js +110 -110
  455. package/lib/uilogic/cloud-provider-contextualizer.d.ts +46 -46
  456. package/lib/uilogic/cloud-provider-contextualizer.js +193 -193
  457. package/lib/uilogic/cloud-resource-configurator-factory.d.ts +41 -41
  458. package/lib/uilogic/cloud-resource-configurator-factory.js +157 -157
  459. package/lib/uilogic/cloud-resource-configurators/aws-k8s-versions.d.ts +11 -0
  460. package/lib/uilogic/cloud-resource-configurators/aws-k8s-versions.js +16 -0
  461. package/lib/uilogic/cloud-resource-configurators/aws-k8s-versions.js.map +1 -0
  462. package/lib/uilogic/cloud-resource-configurators/aws-node-types.d.ts +5 -0
  463. package/lib/uilogic/cloud-resource-configurators/aws-node-types.js +536 -0
  464. package/lib/uilogic/cloud-resource-configurators/aws-node-types.js.map +1 -0
  465. package/lib/uilogic/cloud-resource-configurators/aws-regions.d.ts +10 -0
  466. package/lib/uilogic/cloud-resource-configurators/aws-regions.js +34 -0
  467. package/lib/uilogic/cloud-resource-configurators/aws-regions.js.map +1 -0
  468. package/lib/uilogic/cloud-resource-configurators/aws-resource-configurator.d.ts +38 -38
  469. package/lib/uilogic/cloud-resource-configurators/aws-resource-configurator.js +347 -347
  470. package/lib/uilogic/cloud-resource-configurators/az-acr-cli-authenticator.js +77 -77
  471. package/lib/uilogic/cloud-resource-configurators/az-interactive-login-configurator.d.ts +42 -42
  472. package/lib/uilogic/cloud-resource-configurators/az-interactive-login-configurator.js +247 -247
  473. package/lib/uilogic/cloud-resource-configurators/azure-resource-configurator.d.ts +110 -110
  474. package/lib/uilogic/cloud-resource-configurators/azure-resource-configurator.js +781 -781
  475. package/lib/uilogic/cloud-resource-configurators/azure-types.js +9 -9
  476. package/lib/uilogic/cloud-resource-configurators/docker-hub-resource-configurator.d.ts +24 -24
  477. package/lib/uilogic/cloud-resource-configurators/docker-hub-resource-configurator.js +105 -105
  478. package/lib/uilogic/cloud-resource-configurators/helm-resource-configurator.d.ts +16 -16
  479. package/lib/uilogic/cloud-resource-configurators/helm-resource-configurator.js +44 -44
  480. package/lib/uilogic/cloud-resource-configurators/unsupported-resource-configurator.d.ts +18 -18
  481. package/lib/uilogic/cloud-resource-configurators/unsupported-resource-configurator.js +61 -61
  482. package/lib/uilogic/enterprise-contextualizer.d.ts +76 -76
  483. package/lib/uilogic/enterprise-contextualizer.js +670 -670
  484. package/lib/uilogic/environment-contextualizer.d.ts +15 -15
  485. package/lib/uilogic/environment-contextualizer.js +42 -42
  486. package/lib/uilogic/i-cluster-configurator.d.ts +9 -9
  487. package/lib/uilogic/i-cluster-configurator.js +2 -2
  488. package/lib/uilogic/i-login-configurator.d.ts +6 -6
  489. package/lib/uilogic/i-login-configurator.js +2 -2
  490. package/lib/uilogic/i-registry-configurator.d.ts +6 -6
  491. package/lib/uilogic/i-registry-configurator.js +2 -2
  492. package/lib/uilogic/i-secret-store-configurator.d.ts +7 -7
  493. package/lib/uilogic/i-secret-store-configurator.js +2 -2
  494. package/lib/uilogic/image-configurator.d.ts +133 -133
  495. package/lib/uilogic/image-configurator.js +577 -577
  496. package/lib/uilogic/image-contextualizer.d.ts +24 -24
  497. package/lib/uilogic/image-contextualizer.js +89 -89
  498. package/lib/uilogic/image-registry-contextualizer.d.ts +28 -28
  499. package/lib/uilogic/image-registry-contextualizer.js +126 -126
  500. package/lib/uilogic/index.d.ts +9 -9
  501. package/lib/uilogic/index.js +13 -13
  502. package/lib/uilogic/prompt-select-fuzzy.js +138 -138
  503. package/lib/uilogic/render-methods.d.ts +12 -12
  504. package/lib/uilogic/render-methods.js +64 -64
  505. package/lib/uilogic/tenant-contextualizer.d.ts +79 -79
  506. package/lib/uilogic/tenant-contextualizer.js +573 -573
  507. package/lib/user-context-loader.d.ts +60 -60
  508. package/lib/user-context-loader.js +183 -183
  509. package/oclif.manifest.json +45 -1
  510. package/package.json +150 -150
  511. package/scaffolding/api/.gitignore-scaffolding +68 -68
  512. package/scaffolding/api/.vscode/launch.json +16 -16
  513. package/scaffolding/api/.vscode/settings.json +7 -7
  514. package/scaffolding/api/.vscode/tasks.json +15 -15
  515. package/scaffolding/api/src/app-config.json +2 -2
  516. package/scaffolding/api/src/index.ts-scaffolding +13 -13
  517. package/scaffolding/api/src/myApiDef.ts-scaffolding +25 -25
  518. package/scaffolding/default/.gitignore-scaffolding +2 -2
  519. package/scaffolding/typescript/.gitignore-scaffolding +69 -69
  520. package/scaffolding/typescript/.vscode/launch.json +16 -16
  521. package/scaffolding/typescript/.vscode/settings.json +7 -7
  522. package/scaffolding/typescript/.vscode/tasks.json +15 -15
@@ -1,1365 +1,1365 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LogStreamer = exports.K8sContainerRef = exports.TermArgs = exports.ConfigFileArgs = exports.ExecArgs = exports.K8S_POD_PHASES = exports.InteractionModes = exports.AssetContentType = exports.PROMPT_ME_DESIGNATOR = void 0;
4
- const tslib_1 = require("tslib");
5
- //import * as path from 'path';
6
- const stream = require("stream");
7
- const core_1 = require("@oclif/core");
8
- const _ = require("lodash");
9
- const SplitCmd = require('split-cmd');
10
- const request = require("request");
11
- const semver = require("semver");
12
- const k8s = require("@kubernetes/client-node");
13
- const codiac_relay_contracts_1 = require("@codiac.io/codiac-relay-contracts");
14
- const command_base_enterprise_1 = require("../../command-base-enterprise");
15
- const render = require("../../uilogic/render-methods");
16
- const cloud_provider_contextualizer_1 = require("../../uilogic/cloud-provider-contextualizer");
17
- const client_node_1 = require("@kubernetes/client-node");
18
- const web_socket_handler_1 = require("@kubernetes/client-node/dist/web-socket-handler");
19
- const codiac_ops_common_1 = require("@codiac.io/codiac-ops-common");
20
- // let logUpdate: any;
21
- // (async function () {
22
- // logUpdate = (await import("log-update")).default;
23
- // })()
24
- // import * as logUpdate from "log-update";
25
- // import logUpdate from "log-update";
26
- // const logUpdate = (await import("log-update/index.js")).default
27
- // import { logUpdate } from "log-update";
28
- // const logUpdate = require("log-update");
29
- const log_update_wrapper_1 = require("../../log-update-wrapper");
30
- const codiac_constants_1 = require("../../codiac-constants");
31
- // const { selectFiles, COMPLETED, CANCELLED } = require('select-files-cli'); // gd js wo ts...
32
- // const { selectFiles, COMPLETED, CANCELLED } = require('../../uilogic/file-selector'); // gd js wo ts...
33
- /** The value provided as input that indicates
34
- * a user's desire to be prompted with a list from which choose the value(s),
35
- * instead of entering them manually or taking a default. */
36
- exports.PROMPT_ME_DESIGNATOR = "?";
37
- var AssetContentType;
38
- (function (AssetContentType) {
39
- AssetContentType["logs"] = "logs";
40
- AssetContentType["term"] = "term";
41
- AssetContentType["exec"] = "exec";
42
- AssetContentType["env"] = "env";
43
- AssetContentType["config"] = "config";
44
- AssetContentType["status"] = "status";
45
- // | "footprint-usage" | "infrx"
46
- // | "ingress-domains" | "ingress-nslookup" | "ingress-routes" | "ingress-logs" | "ssl-certs" | "ssl-logs" | "ssl-cert-history";
47
- })(AssetContentType = exports.AssetContentType || (exports.AssetContentType = {}));
48
- const DEFAULT_TERMINAL_STARTER = "bash";
49
- /** The quantity of lines of backlog to include in the log output. */
50
- const DEFAULT_LOG_TAIL = 10;
51
- var InteractionModes;
52
- (function (InteractionModes) {
53
- InteractionModes["echo"] = "echo";
54
- InteractionModes["toscript"] = "toscript";
55
- InteractionModes["silent"] = "silent";
56
- })(InteractionModes = exports.InteractionModes || (exports.InteractionModes = {}));
57
- /** This belongs to k8s - not us, but @kubernetes/client-node has no enum or constants for these magic strings...
58
- *
59
- * @see https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
60
- */
61
- var K8S_POD_PHASES;
62
- (function (K8S_POD_PHASES) {
63
- K8S_POD_PHASES["Pending"] = "Pending";
64
- K8S_POD_PHASES["Running"] = "Running";
65
- K8S_POD_PHASES["Succeeded"] = "Succeeded";
66
- K8S_POD_PHASES["Failed"] = "Failed";
67
- K8S_POD_PHASES["Unknown"] = "Unknown";
68
- })(K8S_POD_PHASES = exports.K8S_POD_PHASES || (exports.K8S_POD_PHASES = {}));
69
- class AssetView extends command_base_enterprise_1.CommandBaseEnterprise {
70
- constructor() {
71
- super(...arguments);
72
- this.takeDefaults = false;
73
- }
74
- get uiCloudPvd() {
75
- if (this._uiCloudPvd_backer === undefined) {
76
- this._uiCloudPvd_backer = this.ioc.get(cloud_provider_contextualizer_1.CloudProviderContextualizer);
77
- }
78
- return this._uiCloudPvd_backer;
79
- }
80
- bootstrap() {
81
- super.bootstrap();
82
- cloud_provider_contextualizer_1.CloudProviderContextualizer.bootstrap(this.ioc); // (idempotent) this is a dependency of the configurators
83
- }
84
- run() {
85
- var _a, _b, _c;
86
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
87
- try {
88
- // ==================================================
89
- // 1. Bootstrap
90
- // ==================================================
91
- this.bootstrap();
92
- // this._relayContainer?.ready$
93
- // .subscribe(async (ready: boolean) => {
94
- // ==================================================
95
- // 2. Gather cli input
96
- // ==================================================
97
- const { args, flags } = yield this.parse(AssetView);
98
- const interactionMode = (_b = (_a = (flags.echo ? InteractionModes.echo : undefined)) !== null && _a !== void 0 ? _a : (flags.toscript ? InteractionModes.toscript : undefined)) !== null && _b !== void 0 ? _b : (flags.silent ? InteractionModes.silent : undefined);
99
- this.takeDefaults = (_c = flags.takeDefaults) !== null && _c !== void 0 ? _c : false;
100
- let partialReq = {};
101
- partialReq.enterprise = flags.enterprise;
102
- partialReq.asset = flags.asset;
103
- partialReq.environment = flags.environment;
104
- partialReq.cabinet = flags.cabinet;
105
- partialReq.content = (flags.type) ? AssetContentType[flags.type] : undefined;
106
- partialReq.replica = flags.replica;
107
- let givenCmd;
108
- if (args.cmd) {
109
- givenCmd = args.cmd;
110
- let isep = this.argv.indexOf("--");
111
- if (isep >= 0) {
112
- if (isep + 1 < this.argv.length) {
113
- givenCmd = this.argv.slice(isep + 1);
114
- }
115
- else {
116
- givenCmd = undefined;
117
- }
118
- }
119
- }
120
- let contentOptions = {
121
- follow: flags.logsFollow,
122
- tailLines: flags.logsTail,
123
- /* tty: flags.tty, */
124
- command: givenCmd,
125
- terminalStartup: flags.terminal,
126
- rootPathName: flags.configFile
127
- };
128
- // ==================================================
129
- // 3. Assemble candidate
130
- // ==================================================
131
- let candidate;
132
- let cmd;
133
- if (interactionMode == InteractionModes.silent) {
134
- candidate = yield this.buildCandidate_silently(partialReq, partialReq.content, contentOptions);
135
- }
136
- else {
137
- [candidate, cmd] = yield this.buildCandidate_interactively(partialReq, contentOptions, partialReq.content);
138
- }
139
- // ==================================================
140
- // 4. Render ultimate command string
141
- // ==================================================
142
- if (interactionMode == InteractionModes.echo || interactionMode == InteractionModes.toscript) {
143
- if (cmd && cmd.length > 0) {
144
- this._ui.userMessage(cmd.join(" "));
145
- }
146
- }
147
- // ==================================================
148
- // 5. Execute
149
- // ==================================================
150
- if (interactionMode != InteractionModes.toscript) {
151
- yield this.renderSelectedContent(candidate.context, candidate.contentType, candidate.k8sEntities, candidate.contentOptions, candidate.replicas);
152
- }
153
- // return;
154
- // });
155
- return;
156
- }
157
- catch (err) {
158
- this.handleError(err);
159
- throw err;
160
- }
161
- });
162
- }
163
- buildCandidate_silently(partialReq, content, contentOptions) {
164
- var _a, _b, _c, _d, _e, _f;
165
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
166
- this.__ui = new codiac_ops_common_1.ThrowingUserInputProvider(this.logger);
167
- if (content === undefined || _.isEmpty(partialReq.content))
168
- throw new Error(`No content type specified.`);
169
- if (partialReq.enterprise === undefined || _.isEmpty(partialReq.enterprise))
170
- throw new Error(`No enterprise specified.`);
171
- if (partialReq.asset === undefined || _.isEmpty(partialReq.asset))
172
- throw new Error(`No asset specified.`);
173
- if (partialReq.environment === undefined || _.isEmpty(partialReq.environment))
174
- throw new Error(`No environment specified.`);
175
- if (partialReq.cabinet === undefined || _.isEmpty(partialReq.cabinet))
176
- throw new Error(`No cabinet specified.`);
177
- // Replica should not be required
178
- // (though this can be confusing when there's more than one;
179
- // the user will have to know they're only getting a single replica of logs,
180
- // and they need to know they might have to call out for one.
181
- // if (partialReq.replica === undefined || _.isEmpty(partialReq.replica)) throw new Error(`No replica specified.`);
182
- let options;
183
- switch (partialReq.content) {
184
- case AssetContentType.logs:
185
- options = (contentOptions !== null && contentOptions !== void 0 ? contentOptions : {});
186
- // defaults?
187
- break;
188
- case AssetContentType.exec:
189
- if (_.isEmpty(contentOptions.command))
190
- throw new Error(`No command specified.`);
191
- options = {
192
- command: contentOptions.command,
193
- tty: (_a = contentOptions.tty) !== null && _a !== void 0 ? _a : false
194
- };
195
- break;
196
- case AssetContentType.config:
197
- if (_.isEmpty(contentOptions.rootPathName))
198
- throw new Error(`No file specified.`);
199
- options = {
200
- rootPathName: contentOptions.rootPathName
201
- };
202
- break;
203
- case AssetContentType.term:
204
- options = {
205
- terminalStartup: (_b = contentOptions.terminalStartup) !== null && _b !== void 0 ? _b : DEFAULT_TERMINAL_STARTER
206
- };
207
- break;
208
- case AssetContentType.env: /* env has no user input */
209
- default:
210
- options = {};
211
- break;
212
- }
213
- // Retrieve the list of replicas for the given cabinet.
214
- let rootMap = yield this.getRootMap(partialReq.enterprise);
215
- let env = this.deriveEnvironmentFrom(partialReq.enterprise, partialReq.cabinet, rootMap); // this is fkng stupid. Put this value into the cab value
216
- let cabObj = this.getCabinetInfrx(partialReq.enterprise, env.name, partialReq.cabinet, rootMap);
217
- if (cabObj.infrx == undefined || _.isEmpty(cabObj.infrx))
218
- throw new Error(`Cannot connect to cabinet ${cabObj.name}: it has no infrastructure record.`);
219
- let k8sObj = { namespace: cabObj.infrx.namespace };
220
- let replicas = yield this.fetchReplicas(partialReq, cabObj.infrx.namespace);
221
- if (replicas.length > 0) {
222
- // Set first as default
223
- partialReq.replica = (_d = (_c = replicas[0].metadata) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : "unnamed";
224
- k8sObj = {
225
- namespace: cabObj.infrx.namespace,
226
- pod: partialReq.replica,
227
- container: (_f = (_e = replicas[0].spec) === null || _e === void 0 ? void 0 : _e.containers[0].name) !== null && _f !== void 0 ? _f : "unnamed"
228
- };
229
- // Select a replica unless it's an asset-level operation
230
- if (content !== AssetContentType.status) {
231
- // This method falls back to first found as default, throws if not enough info is provided
232
- k8sObj = yield this.promptForReplica(replicas, undefined, partialReq.replica);
233
- partialReq.replica = k8sObj.pod;
234
- }
235
- }
236
- // Assemble
237
- let candidate = {
238
- context: {
239
- enterprise: partialReq.enterprise,
240
- environment: partialReq.environment,
241
- asset: partialReq.asset,
242
- cabinet: partialReq.cabinet,
243
- replica: partialReq.replica
244
- },
245
- contentType: content,
246
- contentOptions: options,
247
- k8sEntities: k8sObj,
248
- replicas: replicas
249
- };
250
- return candidate;
251
- });
252
- }
253
- buildCandidate_interactively(partialReq, contentOptions, content) {
254
- var _a, _b, _c, _d;
255
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
256
- this._userCntx = yield this.establishTenantContext(this._userCntx);
257
- let enterprise = (yield this.establishEnterpriseContext()).enterprise;
258
- partialReq.enterprise = enterprise.code;
259
- let rootMap = yield this.getRootMap(enterprise.code);
260
- let replicas;
261
- let k8sObj;
262
- let confirmed = false;
263
- let optionsArgs = [];
264
- do {
265
- // 1. Select Asset
266
- partialReq.asset = yield this.promptForAsset(enterprise.assets, partialReq.asset);
267
- // 2. Cabinet
268
- let cabObj = yield this.promptForCabinet(partialReq.enterprise, rootMap, partialReq.cabinet);
269
- partialReq.cabinet = cabObj.name;
270
- partialReq.environment = this.deriveEnvironmentFrom(partialReq.enterprise, partialReq.cabinet, rootMap).name;
271
- let cluster = this.deriveClusterFrom(partialReq.enterprise, partialReq.environment, partialReq.cabinet, rootMap);
272
- // partialReq.cabinet = await this.establishCabinetContext(partialReq.cabinet);
273
- if (cabObj.infrx == undefined || _.isEmpty(cabObj.infrx))
274
- throw new Error(`Cannot connect to cabinet ${cabObj.name}: it has no infrastructure record.`);
275
- k8sObj = { namespace: cabObj.infrx.namespace };
276
- // 3. Content type
277
- content = yield this.promptForContentType(content);
278
- // 4. Content-specific arguments
279
- // MarkStartHere("implement prompt-me designator.")
280
- // MarkStartHere("Support the current logger or ioc ctr inside the ws event handlers");
281
- // MarkStartHere("Need UI to operate a different stream than stdout (so piping stdout wont include the ui content");
282
- [contentOptions, optionsArgs] = yield this.promptForContentOptions(content, partialReq, contentOptions);
283
- // 5. Authenticate with CSP
284
- this.uiCloudPvd.takeDefaults = this.takeDefaults;
285
- yield this.uiCloudPvd.promptForCloudProviderCreds(this.ioc, cluster.provider);
286
- // 6. Replica (Pod)
287
- if (cabObj.infrx == undefined || _.isEmpty(cabObj.infrx))
288
- throw new Error(`Cannot connect to cabinet ${cabObj.name}: it has no infrastructure record.`);
289
- replicas = yield this.fetchReplicas(partialReq, cabObj.infrx.namespace);
290
- if (replicas.length > 0) {
291
- // Set first as default
292
- partialReq.replica = (_b = (_a = replicas[0].metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "unnamed";
293
- k8sObj = {
294
- namespace: cabObj.infrx.namespace,
295
- pod: partialReq.replica,
296
- container: (_d = (_c = replicas[0].spec) === null || _c === void 0 ? void 0 : _c.containers[0].name) !== null && _d !== void 0 ? _d : "unnamed"
297
- };
298
- // Select a replica unless it's an asset-level operation
299
- if (content !== AssetContentType.status) {
300
- k8sObj = yield this.promptForReplica(replicas, undefined, partialReq.replica);
301
- partialReq.replica = k8sObj.pod;
302
- }
303
- }
304
- // 7. Confirm or loop back around to enterprise
305
- confirmed = true; // This is a readonly ui (no danger), and we want to enable fast switching among diff content types, so let's not waste time confirming. // await this._ui.promptConfirm("confirm", "Apply? ");
306
- } while (!confirmed);
307
- // We're hard-coding instead of casting here to validate at build-time that each partial property is fully-hydrated.
308
- // Assemble
309
- let candidate = {
310
- context: {
311
- enterprise: partialReq.enterprise,
312
- environment: partialReq.environment,
313
- asset: partialReq.asset,
314
- cabinet: partialReq.cabinet,
315
- replica: partialReq.replica
316
- },
317
- contentType: content,
318
- contentOptions: contentOptions,
319
- k8sEntities: k8sObj,
320
- replicas: replicas
321
- };
322
- // Build command string
323
- let cmd = ["cod", "asset", "view"];
324
- cmd.push("--silent");
325
- cmd.push("-e", candidate.context.enterprise);
326
- cmd.push("-a", candidate.context.asset);
327
- cmd.push("-n", candidate.context.environment);
328
- cmd.push("-c", candidate.context.cabinet);
329
- if (candidate.context.replica)
330
- cmd.push("-r", candidate.context.replica);
331
- cmd.push("-t", candidate.contentType);
332
- cmd.push(...optionsArgs);
333
- return [candidate, cmd];
334
- });
335
- }
336
- promptForContentOptions(contentType, context, defaults) {
337
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
338
- let cmdArgs = [];
339
- try {
340
- switch (contentType) {
341
- case AssetContentType.logs:
342
- let logArgs = yield this.promptForLogOptions(defaults);
343
- if (logArgs.follow)
344
- cmdArgs.push("-f");
345
- if (logArgs.tailLines)
346
- cmdArgs.push(...["-l", "" + logArgs.tailLines]);
347
- return [logArgs, cmdArgs];
348
- case AssetContentType.exec:
349
- let execArgs = yield this.promptForExecOptions(defaults);
350
- cmdArgs.push(...execArgs.command);
351
- return [execArgs, cmdArgs];
352
- case AssetContentType.config:
353
- this.enterpriseContextor.takeDefaults = this.takeDefaults;
354
- let rootPathName = (yield this.enterpriseContextor.promptForTargetFile(context.enterprise, context.asset, defaults === null || defaults === void 0 ? void 0 : defaults.rootPathName));
355
- let cfgArgs = { rootPathName: rootPathName };
356
- cmdArgs.push("-F", rootPathName);
357
- return [cfgArgs, cmdArgs];
358
- case AssetContentType.term:
359
- let termArgs = yield this.promptForTerminalOptions(defaults);
360
- if (termArgs.terminalStartup)
361
- cmdArgs.push(...["--terminal", termArgs.terminalStartup]);
362
- return [termArgs, cmdArgs];
363
- default:
364
- return [{}, []];
365
- }
366
- }
367
- catch (err) {
368
- throw err;
369
- }
370
- });
371
- }
372
- promptForLogOptions(defaults) {
373
- var _a, _b;
374
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
375
- let options = (defaults !== null && defaults !== void 0 ? defaults : {});
376
- options.follow = (_a = options.follow) !== null && _a !== void 0 ? _a : true;
377
- if (!this.takeDefaults) {
378
- options.follow = yield this._ui.promptConfirm("follow", "Stream logs? ", options.follow);
379
- }
380
- options.tailLines = (_b = options.tailLines) !== null && _b !== void 0 ? _b : DEFAULT_LOG_TAIL;
381
- if (!this.takeDefaults) {
382
- options.tailLines = yield this._ui.prompt("tail", "Lines of backlog (-1 for all):", true, options.tailLines);
383
- }
384
- return options;
385
- });
386
- }
387
- promptForExecOptions(defaults) {
388
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
389
- let options = (defaults !== null && defaults !== void 0 ? defaults : {});
390
- // Command
391
- let cmdStr;
392
- let keep = this.takeDefaults;
393
- if (!_.isEmpty(options.command) && !this.takeDefaults) {
394
- cmdStr = (typeof options.command === 'string') ? options.command : options.command.join(" ");
395
- keep = yield this._ui.promptConfirm("keepCommand", `Command: ${this._styler.hilite(cmdStr)} `);
396
- }
397
- if (keep && !_.isEmpty(options.command)) {
398
- // do nothing
399
- }
400
- else {
401
- options.command = (yield this._ui.prompt("command", "Command: ", true, cmdStr));
402
- options.command = SplitCmd.split(options.command); // no types declarations - f#$&*ing script kiddie.
403
- // the one above trips on the --output flag in this: kubectl get pods -n cod-zombie-v1 -l assetNamme=codiac-api --output=jsonpath="{.items[*]['metadata.name', 'status.capacity']}"
404
- // something safer than: options.command = options.command.split(" ");
405
- }
406
- return options;
407
- });
408
- }
409
- promptForTerminalOptions(defaults) {
410
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
411
- let options = (defaults !== null && defaults !== void 0 ? defaults : {});
412
- // Command
413
- let keep = this.takeDefaults;
414
- if (!_.isEmpty(options.terminalStartup) && !this.takeDefaults) {
415
- keep = yield this._ui.promptConfirm("keepStartup", `Terminal Startup: ${this._styler.hilite(options.terminalStartup)} `);
416
- }
417
- if (keep && !_.isEmpty(options.terminalStartup)) {
418
- // do nothing
419
- }
420
- else {
421
- options.terminalStartup = (yield this._ui.prompt("startup", "Terminal Startup: ", true, options.terminalStartup));
422
- }
423
- return options;
424
- });
425
- }
426
- promptForContentType(defaultValue) {
427
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
428
- try {
429
- let output;
430
- let choices = Object.keys(AssetContentType);
431
- let keep = this.takeDefaults;
432
- if (defaultValue && choices.find(x => x == defaultValue) && !this.takeDefaults) {
433
- keep = yield this._ui.promptConfirm("keepType", `Type of content: ${this._styler.hilite(defaultValue)} `);
434
- }
435
- if (keep && defaultValue !== undefined) {
436
- output = defaultValue;
437
- }
438
- else {
439
- output = (yield this._ui.promptSelect("type", "Type of content: ", choices));
440
- }
441
- return output;
442
- }
443
- catch (err) {
444
- throw err;
445
- }
446
- });
447
- }
448
- promptForAsset(assets, defaultValue) {
449
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
450
- try {
451
- let output;
452
- let choices = assets.map(a => { return { name: a.name, value: a.name }; });
453
- choices = _.orderBy(choices, c => c.name);
454
- /** If we changed the input they provided, we need their confirmation (whether or not they said takeDefaults) */
455
- let changedUserInput = false;
456
- if (choices.length === 1) {
457
- if (defaultValue != choices[0].value) {
458
- changedUserInput = !_.isEmpty(defaultValue);
459
- defaultValue = choices[0].value;
460
- }
461
- }
462
- let keep = this.takeDefaults;
463
- if (defaultValue && choices.find(x => x.value == defaultValue) && (changedUserInput || !this.takeDefaults)) {
464
- keep = yield this._ui.promptConfirm("keepAsset", `Asset: ${this._styler.hilite(defaultValue)} `);
465
- }
466
- if (keep && defaultValue !== undefined) {
467
- output = defaultValue;
468
- }
469
- else {
470
- output = (yield this._ui.promptSelect("asset", "Asset: ", choices));
471
- }
472
- return output;
473
- }
474
- catch (err) {
475
- throw err;
476
- }
477
- });
478
- }
479
- promptForCabinet(enterprise, rootMap, defaultValue) {
480
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
481
- try {
482
- let output;
483
- // render cab tree with all lines selectable
484
- let cabTree = this.buildCabinetTree(rootMap);
485
- let choices = this.buildSelectChoicesFrom(cabTree);
486
- // ISSUES:
487
- // 0. Remove the freaking lines from the selected value.
488
- // 1. Remember the last cabinet (user's enterprise context).
489
- // 2. We should only render the cabinets that actually contain a deployment of the asset (or dim the others and loop back if selected)
490
- // 3. The picklist should render the cluster (provider, name, location)
491
- // 4. PERHAPS? The version of the asset running in the selected cabinet should get rendered (either in the picklist or after the cab is selected)
492
- /** If we changed the input they provided, we need their confirmation (whether or not they said takeDefaults) */
493
- const CAB_PREFIX = "cabinet|";
494
- let cabChoices = choices.filter(c => c.value.startsWith(CAB_PREFIX));
495
- let changedUserInput = false;
496
- if (cabChoices.length === 1) {
497
- if (defaultValue != cabChoices[0].value.slice(CAB_PREFIX.length)) {
498
- changedUserInput = !_.isEmpty(defaultValue);
499
- defaultValue = cabChoices[0].value.slice(CAB_PREFIX.length);
500
- }
501
- }
502
- let keep = this.takeDefaults;
503
- if (defaultValue && Boolean(choices.find(x => x.value === `${CAB_PREFIX}${defaultValue}`)) && (changedUserInput || !this.takeDefaults)) {
504
- keep = yield this._ui.promptConfirm("keepCabinet", `Cabinet: ${this._styler.hilite(defaultValue)} `);
505
- }
506
- if (keep && defaultValue !== undefined) {
507
- output = defaultValue;
508
- }
509
- else {
510
- let scope;
511
- let target;
512
- do {
513
- if (scope === "environment") {
514
- // we could just filter it down from here...
515
- }
516
- let selection = (yield this._ui.promptSelect("cabinet", "Cabinet: ", choices, false, false));
517
- let parts = selection.split("|");
518
- scope = parts[0];
519
- target = parts[1];
520
- } while (scope !== "cabinet"); // ensure they select a cabinet
521
- output = target;
522
- }
523
- let env = this.deriveEnvironmentFrom(enterprise, output, rootMap); // this is fkng stupid. Put this value into the cab value
524
- let cabObj = this.getCabinetInfrx(enterprise, env.name, output, rootMap);
525
- // return output;
526
- return cabObj;
527
- }
528
- catch (err) {
529
- throw (err);
530
- }
531
- });
532
- }
533
- deriveEnvironmentFrom(enterprise, cabinet, rootMap) {
534
- try {
535
- let ent = rootMap.enterprises.find(e => e.name === enterprise);
536
- if (ent === undefined)
537
- throw new Error(`Cannot find environment: did not recognize enterprise [${enterprise}]`);
538
- let enviro = ent.environments.find(x => x.cabinets.find(c => c.name === cabinet));
539
- if (enviro === undefined)
540
- throw new Error(`Cannot find environment: did not recognize cabinet [${cabinet}]`);
541
- return enviro;
542
- }
543
- catch (err) {
544
- throw err;
545
- }
546
- }
547
- deriveClusterFrom(enterprise, environment, cabinet, rootMap) {
548
- try {
549
- let ent = rootMap.enterprises.find(e => e.name === enterprise);
550
- if (ent === undefined)
551
- throw new Error(`Cannot find cluster: did not recognize enterprise [${enterprise}]`);
552
- let enviro = ent.environments.find(x => x.cabinets.find(c => c.name === cabinet));
553
- if (enviro === undefined)
554
- throw new Error(`Cannot find cluster: did not recognize cabinet [${cabinet}]`);
555
- let cabObj = enviro.cabinets.find(c => c.name === cabinet);
556
- if (cabObj == undefined)
557
- throw new Error(`Cannot find cluster: did not recognize cabinet [${cabinet}]`);
558
- if (cabObj.cluster == undefined)
559
- throw new Error(`Cannot find cluster: cabinet [${cabinet}] does not have a cluster specified.`);
560
- let cluster = rootMap.clusters.find(c => c.name == cabObj.cluster);
561
- if (cluster == undefined)
562
- throw new Error(`Did not recognize cluster [${cabObj.cluster}]`);
563
- return cluster;
564
- }
565
- catch (err) {
566
- throw err;
567
- }
568
- }
569
- buildSelectChoicesFrom(tree) {
570
- try {
571
- let choices = [];
572
- // the value is no good here - need scope and target both available
573
- render.renderStringTree(tree, (txt, item) => choices.push({ name: txt, value: item.value }));
574
- // // This is one way to do it
575
- // for (let item of tree) {
576
- //
577
- // let thisChoice: PromptChoice = { name: item.text, value: item.text };
578
- // choices.push(thisChoice);
579
- //
580
- // if (item.children && item.children.length > 0) {
581
- // let children = this.buildSelectChoicesFrom(item.children);
582
- // choices.push(...children);
583
- // }
584
- // }
585
- return choices;
586
- }
587
- catch (err) {
588
- throw err;
589
- }
590
- }
591
- /** sets each value to "scope|target".
592
- *
593
- * This is MOSTLY a COPY-PASTE from the CabinetList command!!! This view is prob gonna be pretty common - consider promoting it to a shared utility. */
594
- buildCabinetTree(rootMap, existings) {
595
- var _a, _b, _c, _d;
596
- let tree = [];
597
- for (let ent of rootMap.enterprises) {
598
- let entBranch = { text: `${ent.name} enterprise:`, value: `${codiac_relay_contracts_1.ScopeLevel.enterprise}|${ent.name}` };
599
- let entSetting = existings === null || existings === void 0 ? void 0 : existings.find(s => s.scope === codiac_relay_contracts_1.ScopeLevel.enterprise && s.target === ent.name);
600
- if (entSetting !== undefined) {
601
- let valueSuffix = this.ellipsis(35, (_a = entSetting.value) !== null && _a !== void 0 ? _a : "[set to undefined]");
602
- valueSuffix = `(${valueSuffix})`;
603
- entBranch.text = entBranch.text.concat(" ", this._styler.dim(valueSuffix));
604
- }
605
- for (let env of _.sortBy(ent.environments, e => e.sequence, e => e.name)) {
606
- let envBranch = { text: `${env.name}`, value: `${codiac_relay_contracts_1.ScopeLevel.environment}|${env.name}` };
607
- let envSetting = existings === null || existings === void 0 ? void 0 : existings.find(s => s.scope === codiac_relay_contracts_1.ScopeLevel.environment && s.target === env.name);
608
- if (envSetting !== undefined) {
609
- let valueSuffix = this.ellipsis(35, (_b = envSetting.value) !== null && _b !== void 0 ? _b : "[set to undefined]");
610
- valueSuffix = `(${valueSuffix})`;
611
- envBranch.text = envBranch.text.concat(" ", this._styler.dim(valueSuffix));
612
- }
613
- for (let cab of env.cabinets) {
614
- // let cwg = rootMap.clusters.find(c => c.name === cab.cluster);
615
- // let clusterDesc = cwg ? ` (${cab.cluster}, ${cwg.provider} ${cwg.locationName})` : "";
616
- let cabBranch = {
617
- text: `${cab.name}`,
618
- value: `${codiac_relay_contracts_1.ScopeLevel.cabinet}|${cab.name}`
619
- };
620
- let cabSetting = existings === null || existings === void 0 ? void 0 : existings.find(s => s.scope === codiac_relay_contracts_1.ScopeLevel.cabinet && s.target === cab.name);
621
- if (cabSetting !== undefined) {
622
- let valueSuffix = this.ellipsis(35, (_c = cabSetting.value) !== null && _c !== void 0 ? _c : "[set to undefined]");
623
- valueSuffix = `(${valueSuffix})`;
624
- cabBranch.text = cabBranch.text.concat(" ", this._styler.dim(valueSuffix));
625
- }
626
- if (envBranch.children === undefined)
627
- envBranch.children = [];
628
- (_d = envBranch.children) === null || _d === void 0 ? void 0 : _d.push(cabBranch);
629
- }
630
- if (entBranch.children === undefined)
631
- entBranch.children = [];
632
- entBranch.children.push(envBranch);
633
- }
634
- tree.push(entBranch);
635
- }
636
- return tree;
637
- }
638
- /** Truncates the string to the given length with an ellipses as suffix */
639
- ellipsis(maxLength, value) {
640
- let output = value;
641
- if (output.length > maxLength) {
642
- let ellipsis = "..."; // Rather use the ellipsis character but String.fromCharCode(133) is returning a problematic character.
643
- output = output.slice(0, maxLength - 1 - ellipsis.length).concat(ellipsis);
644
- }
645
- return output;
646
- }
647
- /**
648
- *
649
- * @param enterprise
650
- * @param environment
651
- * @param cabinet
652
- * @param asset
653
- * @param ctrInPod (Optional, defaults to the first one in the spec) The name of the running container (not the image) inside the pod (relevant only when there's more than one).
654
- * @param defaultValue
655
- * @returns
656
- */
657
- promptForReplica(replicas, ctrInPod, defaultValue) {
658
- var _a, _b, _c, _d, _e;
659
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
660
- try {
661
- let podName;
662
- // params: enterprise: string, environment: string, cabinet: string, asset: string
663
- // // Retrieve replicas
664
- // this._ui.startSpinner(`Fetching ${asset} replicas in ${environment}/${cabinet}...`)
665
- // let reps = await this.genRelayClient.Call.assetStatus({ assetName: asset, cabinetName: cabinet, enterpriseCode: enterprise, environment: environment });
666
- // this._ui.stopSpinner((reps.successes) ? `${reps.successes.length} found.` : "failed.")
667
- // if (reps.error) throw reps.error;
668
- // if (reps.successes == undefined || reps.successes.length === 0) throw new Error(`No ${asset} replicas exist in cabinet ${environment}/${cabinet}. ${reps.message ?? ""}`);
669
- //
670
- // let replicas = reps.successes[0].currentVersion.pods; // <--- HEY!!! Relay shouldnt be exposing raw k8s contracts here - this shd be a codiac contract
671
- let choices = replicas.filter(r => { var _a; return ((_a = r.metadata) === null || _a === void 0 ? void 0 : _a.name) !== undefined; })
672
- .map(r => { var _a, _b, _c; return ({ name: `${(_a = r.metadata.name) !== null && _a !== void 0 ? _a : ""} (${(_b = r.status) === null || _b === void 0 ? void 0 : _b.phase})`, value: (_c = r.metadata.name) !== null && _c !== void 0 ? _c : "" }); });
673
- // Select a replica...
674
- if (choices.length === 0) {
675
- this._ui.userMessage(`No replicas found.`);
676
- podName = "unknown";
677
- // return undefined; // <--- this is what we should do here.
678
- }
679
- else if (choices.length === 1) {
680
- podName = choices[0].value;
681
- this._ui.userMessage(`1 replica found: ${this._styler.hilite(podName)}`);
682
- }
683
- else {
684
- let keep = this.takeDefaults;
685
- if (defaultValue && Boolean(choices.find(x => x.value === defaultValue)) && !this.takeDefaults) {
686
- keep = yield this._ui.promptConfirm("keepReplica", `Replica: ${this._styler.hilite(defaultValue)} `);
687
- }
688
- if (keep && defaultValue !== undefined) {
689
- podName = defaultValue;
690
- }
691
- else {
692
- podName = (yield this._ui.promptSelect("replica", "Replica...", choices, false, false)); // Assertion operator ok here - we're not allowing undefined options.
693
- }
694
- }
695
- let replica = (replicas.find(r => { var _a; return ((_a = r.metadata) === null || _a === void 0 ? void 0 : _a.name) === podName; })); // Assertion ok: selection was already limited to this list.
696
- // Select the container inside...
697
- let containerName;
698
- if ((((_a = replica.spec) === null || _a === void 0 ? void 0 : _a.containers) == undefined) || (((_b = replica.spec) === null || _b === void 0 ? void 0 : _b.containers.length) === 0))
699
- throw new Error("No containers are specified in that replica");
700
- if (!_.isEmpty(ctrInPod)) {
701
- let found = replica.spec.containers.find(c => c.name === ctrInPod);
702
- if (!found)
703
- throw new Error(`Container [${ctrInPod}] not found in that replica`);
704
- containerName = found.name;
705
- }
706
- else {
707
- containerName = replica.spec.containers[0].name;
708
- if (((_c = replica.spec) === null || _c === void 0 ? void 0 : _c.containers.length) > 1) {
709
- // TODO: promptSelect from the list of containers
710
- this._ui.userMessage(`${(_d = replica.spec) === null || _d === void 0 ? void 0 : _d.containers.length} containers in that replica; selected ${containerName}`);
711
- }
712
- }
713
- let k8sCtr = {
714
- namespace: (_e = replica.metadata) === null || _e === void 0 ? void 0 : _e.namespace,
715
- pod: podName,
716
- container: containerName
717
- };
718
- return k8sCtr;
719
- }
720
- catch (err) {
721
- throw err;
722
- }
723
- });
724
- }
725
- renderSelectedContent(context, contentType, k8sEntities, contentOptions, replicas) {
726
- var _a;
727
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
728
- try {
729
- switch (contentType) {
730
- case (AssetContentType.logs):
731
- if (context.replica == undefined)
732
- throw new Error("No replica selected.");
733
- if (k8sEntities.pod == undefined || k8sEntities.container == undefined)
734
- throw new Error("No replica selected.");
735
- yield this.showLogs(context, contentOptions);
736
- break;
737
- case (AssetContentType.term):
738
- if (context.replica == undefined)
739
- throw new Error("No replica selected.");
740
- if (k8sEntities.pod == undefined || k8sEntities.container == undefined)
741
- throw new Error("No replica selected.");
742
- let termArgs = { tty: true, command: (_a = contentOptions === null || contentOptions === void 0 ? void 0 : contentOptions.terminalStartup) !== null && _a !== void 0 ? _a : DEFAULT_TERMINAL_STARTER };
743
- yield this.runExec(context, termArgs, k8sEntities);
744
- break;
745
- case (AssetContentType.exec):
746
- if (context.replica == undefined)
747
- throw new Error("No replica selected.");
748
- if (k8sEntities.pod == undefined || k8sEntities.container == undefined)
749
- throw new Error("No replica selected.");
750
- let execArgs = contentOptions;
751
- execArgs.tty = false; // and we want a run-once behavior so the ws closes after the command completes.
752
- yield this.runExec(context, execArgs, k8sEntities);
753
- break;
754
- case (AssetContentType.config):
755
- if (context.replica == undefined)
756
- throw new Error("No replica selected.");
757
- if (k8sEntities.pod == undefined || k8sEntities.container == undefined)
758
- throw new Error("No replica selected.");
759
- let cfgInput = contentOptions;
760
- if (!cfgInput.rootPathName.startsWith("/"))
761
- cfgInput.rootPathName = "/".concat(cfgInput.rootPathName);
762
- let cfgExec = { tty: false, command: ["cat", cfgInput.rootPathName] };
763
- yield this.runExec(context, cfgExec, k8sEntities);
764
- break;
765
- case (AssetContentType.env):
766
- if (context.replica == undefined)
767
- throw new Error("No replica selected.");
768
- if (k8sEntities.pod == undefined || k8sEntities.container == undefined)
769
- throw new Error("No replica selected.");
770
- let envArgs = { tty: false, command: "env" };
771
- yield this.runExec(context, envArgs, k8sEntities);
772
- break;
773
- case (AssetContentType.status):
774
- // await this.watchEvents(context, k8sEntities.namespace, replicas);
775
- yield this.watchStatus_NEW(context, k8sEntities.namespace, replicas);
776
- // await this.watchStatus(context, k8sEntities.namespace, replicas);
777
- // await this.watchReplicaSet(context, k8sEntities.namespace);
778
- // await this.showStatus(context, k8sEntities.namespace, replicas);
779
- break;
780
- default:
781
- this.logger.debug(`Content type ${contentType} is not yet supported.`, [context, contentType, contentOptions]);
782
- this._ui.userMessage(`Content type ${contentType} is not yet supported.`);
783
- }
784
- return;
785
- }
786
- catch (err) {
787
- throw (err);
788
- }
789
- });
790
- }
791
- getKubeConfig(context) {
792
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
793
- // Retrieve cluster connection specs
794
- let res = yield this.genRelayClient.Call.getClusterConnectionSpecs({
795
- enterprise: context.enterprise,
796
- environment: context.environment,
797
- cabinet: context.cabinet
798
- });
799
- if (res.error)
800
- throw res.error;
801
- if (res.output == undefined || _.isEmpty(res.output)) {
802
- this.log(`Failed loading cluster spec: ${res.message}.`);
803
- throw new Error(`Failed loading cluster spec: ${res.message}.`);
804
- }
805
- // Create the k8s client
806
- let k8sConfig = new client_node_1.KubeConfig();
807
- k8sConfig.loadFromString(res.output);
808
- return k8sConfig;
809
- });
810
- }
811
- getK8sClient(context, kube) {
812
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
813
- let k8sConfig = kube !== null && kube !== void 0 ? kube : (yield this.getKubeConfig(context));
814
- let theirApi = k8sConfig.makeApiClient(k8s.CoreV1Api);
815
- return theirApi;
816
- });
817
- }
818
- /** Gets the cluster cnxn specs from the relay, then makes the k8s call from the cli.
819
- *
820
- * Throws any errors. */
821
- fetchReplicas(context, namespace, k8sClient) {
822
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
823
- try {
824
- let theirApi = k8sClient !== null && k8sClient !== void 0 ? k8sClient : yield this.getK8sClient(context);
825
- // Fetch from the cluster
826
- let podResult = yield theirApi.listNamespacedPod(namespace, undefined, undefined, undefined, undefined, `${codiac_constants_1.CodiacLabels.LABEL_ASSET_NAME}=${context.asset}`);
827
- let replicas = podResult.body.items;
828
- // let replicas = _.orderBy(podResult.body.items, p => p.metadata?.labels?.assetVersion, 'desc'); // NOTE: this isnt a semantic version sort
829
- try {
830
- // Might need a semver.coerce() in here...
831
- replicas = replicas.sort((a, b) => { var _a, _b, _c, _d, _e, _f; return semver.rcompare((_c = (_b = (_a = a.metadata) === null || _a === void 0 ? void 0 : _a.labels) === null || _b === void 0 ? void 0 : _b.assetVersion) !== null && _c !== void 0 ? _c : "", (_f = (_e = (_d = b.metadata) === null || _d === void 0 ? void 0 : _d.labels) === null || _e === void 0 ? void 0 : _e.assetVersion) !== null && _f !== void 0 ? _f : ""); }); // removes semvers so they can be sorted uniquely
832
- }
833
- catch (err) {
834
- replicas = _.orderBy(replicas, p => { var _a, _b, _c; return (_c = (_b = (_a = p.metadata) === null || _a === void 0 ? void 0 : _a.labels) === null || _b === void 0 ? void 0 : _b.assetVersion) !== null && _c !== void 0 ? _c : ""; }); // TODO: we need this ALSO sorted by replica set (ie: name or labels["pod-template-hash"])
835
- }
836
- return replicas;
837
- }
838
- catch (err) {
839
- throw err;
840
- }
841
- });
842
- }
843
- // protected async watchEvents(context: AssetReplicaContext, namespace: string, replicas?: k8s.V1Pod[] | undefined): Promise<void> {
844
- // // let selector = `${CodiacLabels.LABEL_ASSET_NAME}=${context.asset}`;
845
- // let selector = `app=${context.asset}`;
846
- // let creds = await this.getKubeConfig(context);
847
- // let k8sClient = creds.makeApiClient(k8s.EventsV1Api);
848
- // let watcher = new Watch(creds);
849
- // watcher.watch(
850
- // '/apis/events.k8s.io/v1/namespaces/{namespace}/events',
851
- // )
852
- // let res = await k8sClient.listNamespacedEvent(namespace, undefined, undefined, undefined, undefined, selector,
853
- // undefined, undefined, undefined, undefined, true, undefined);
854
- // }
855
- watchStatus_NEW(context, namespace, replicas) {
856
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
857
- // let selector = `${CodiacLabels.LABEL_ASSET_NAME}=${context.asset}`;
858
- let selector = `app=${context.asset}`;
859
- let kube = yield this.getKubeConfig(context);
860
- let k8sClient = yield this.getK8sClient(context);
861
- (0, log_update_wrapper_1.logUpdate)(`Watching ${this._styler.hilite(context.asset)} in ${context.environment}/${context.cabinet}... (ctrl-c to quit)`);
862
- log_update_wrapper_1.logUpdate.done();
863
- (0, log_update_wrapper_1.logUpdate)(`...empty...`);
864
- // This approach DOES return what's different in the cached list,
865
- // but doesnt stream updates from the cluster - it only runs a first request,
866
- // meaning you need to call this repeatedly - this looks not fully-baked...?
867
- let informer = (0, client_node_1.makeInformer)(kube, `/api/v1/namespaces/${namespace}/pods`, () => k8sClient.listNamespacedPod(namespace, undefined, undefined, undefined, undefined, selector)
868
- // () => k8sClient.listNamespacedPod(namespace, undefined, undefined, undefined, undefined, selector, undefined, undefined, undefined, undefined, true),
869
- // selector
870
- );
871
- // informer.on('add', (obj: k8s.V1Pod) => { console.log(`Added: ${obj.metadata!.name}`); });
872
- // informer.on('update', (obj: k8s.V1Pod) => { console.log(`Updated: ${obj.metadata!.name}`); });
873
- informer.on('change', (obj) => {
874
- // console.log(`Changed: ${obj.metadata!.name}`);
875
- let canvas = { table: "", curver: "" };
876
- let replicas = informer.list(namespace);
877
- if (replicas.length > 0) {
878
- for (let pod of replicas) {
879
- this.renderReplicaStatusRow(pod, canvas);
880
- }
881
- }
882
- else {
883
- canvas.table = "(no instances found)";
884
- }
885
- log_update_wrapper_1.logUpdate.clear();
886
- (0, log_update_wrapper_1.logUpdate)(canvas.table);
887
- });
888
- // informer.on('delete', (obj: k8s.V1Pod) => { console.log(`Deleted: ${obj.metadata!.name}`); });
889
- informer.on('error', (err) => {
890
- if (err.statusCode === 401) {
891
- // TODO: reach out to the relay to refresh the user token in the kubeconfig.
892
- log_update_wrapper_1.logUpdate.clear();
893
- (0, log_update_wrapper_1.logUpdate)(`Authentication error; please refresh your credentials.`);
894
- }
895
- else {
896
- log_update_wrapper_1.logUpdate.clear();
897
- console.error(err);
898
- }
899
- // Restart informer after 5sec
900
- setTimeout(() => {
901
- informer.start();
902
- }, 5000);
903
- });
904
- informer.start();
905
- // let watch: boolean = true;
906
- // listNamespacedPod() with "watch" just floats out into space with no return
907
- // let podResult = await k8sClient.listNamespacedPod(namespace, undefined, undefined, undefined, undefined,
908
- // `${CodiacLabels.LABEL_ASSET_NAME}=${context.asset}`, undefined, undefined, undefined, undefined, watch);
909
- // while (podResult) {
910
- // logUpdate(`${podResult.body.items.length} pods returned`); // Thanks, nice and ambiguous; lets give them something actionable here instead.
911
- // }
912
- });
913
- }
914
- watchReplicaSet(context, namespace, replicaSets) {
915
- var _a, _b, _c, _d, _e, _f, _g;
916
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
917
- let k8sConfig = (yield this.getKubeConfig(context));
918
- let k8sClient = k8sConfig.makeApiClient(k8s.AppsV1Api);
919
- // let selector = `${CodiacLabels.LABEL_ASSET_NAME}=${context.asset}`;
920
- let selector = `app=${context.asset}`;
921
- let watch = true;
922
- do {
923
- let content = "";
924
- log_update_wrapper_1.logUpdate.clear();
925
- try {
926
- let podResult = yield k8sClient.listNamespacedReplicaSet(namespace, undefined, undefined, undefined, undefined, selector);
927
- let output = podResult.body.items;
928
- for (let item of output) {
929
- if (item.status) {
930
- content = content.concat(`${(_b = (_a = item.metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "unnamed"} ${(_c = item.status.availableReplicas) !== null && _c !== void 0 ? _c : 0}/${item.status.replicas}`, "\n");
931
- }
932
- else {
933
- content = content.concat(`no status for ${(_e = (_d = item.metadata) === null || _d === void 0 ? void 0 : _d.name) !== null && _e !== void 0 ? _e : "unnamed"}`, "\n");
934
- }
935
- }
936
- }
937
- catch (err) {
938
- content = content.concat(`Error ${(_f = err.name) !== null && _f !== void 0 ? _f : ""} ${(_g = err.message) !== null && _g !== void 0 ? _g : ""}`, "\n");
939
- }
940
- (0, log_update_wrapper_1.logUpdate)(content);
941
- yield this.unblockAndSleep(0.5);
942
- } while (watch);
943
- });
944
- }
945
- watchStatus(context, namespace, replicas) {
946
- var _a, _b, _c, _d, _e, _f, _g;
947
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
948
- let watch = true;
949
- let k8sClient = yield this.getK8sClient(context);
950
- let pods = replicas;
951
- let spinChars = ["|", "/", "-", "\\"];
952
- let spinIndex = -1;
953
- (0, log_update_wrapper_1.logUpdate)(`Status for ${context.asset} in ${context.environment}/${context.cabinet}... (ctrl-c to quit)`);
954
- log_update_wrapper_1.logUpdate.done();
955
- do {
956
- // await this.showStatus(context, namespace, pods, k8sClient);
957
- spinIndex++;
958
- if (spinIndex >= spinChars.length)
959
- spinIndex = 0;
960
- let spinner = spinChars[spinIndex];
961
- // TODO: trap failures here and if status currently exists, render the error and leave the existing
962
- let table = "";
963
- try {
964
- pods = pods !== null && pods !== void 0 ? pods : yield this.fetchReplicas(context, namespace, k8sClient);
965
- if (pods && pods.length > 0) {
966
- log_update_wrapper_1.logUpdate.clear();
967
- let curver = ""; // current asset version being listed
968
- // let deployed = res.successes[0].currentVersion.deployed;
969
- for (let replica of pods) {
970
- let replicaName = (_b = (_a = replica.metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "unnamed";
971
- let podHash = ((_c = replica.metadata) === null || _c === void 0 ? void 0 : _c.labels) ? (_d = replica.metadata) === null || _d === void 0 ? void 0 : _d.labels["pod-template-hash"] : undefined;
972
- let replicaId = podHash ? replicaName.slice(replicaName.indexOf(podHash)) : replicaName;
973
- let assetVersion = ((_e = replica.metadata) === null || _e === void 0 ? void 0 : _e.labels) ? (_f = replica.metadata) === null || _f === void 0 ? void 0 : _f.labels[codiac_constants_1.CodiacLabels.LABEL_ASSET_VERSION] : undefined;
974
- // Version separator
975
- if (assetVersion !== undefined && assetVersion !== curver) {
976
- curver = assetVersion;
977
- table = table.concat(`${spinner} ${assetVersion}`, "\n");
978
- }
979
- // Each replica
980
- if (replica.status) {
981
- let state = this.renderPodState(replica);
982
- let condition = this.renderCondition(replica);
983
- let restarts = (replica.status.containerStatuses && replica.status.containerStatuses.length > 0) ? replica.status.containerStatuses[0].restartCount : 0;
984
- table = table.concat(` ${replicaId}) ${state} ${condition} started (${replica.status.startTime}) ${restarts} restarts\n`); // , deployed (${deployed})`)
985
- }
986
- }
987
- }
988
- else {
989
- table = table.concat(`No running instances found.`);
990
- }
991
- }
992
- catch (err) {
993
- table = table.concat(`Error refreshing... ${(_g = err.message) !== null && _g !== void 0 ? _g : err.name}\n`);
994
- }
995
- (0, log_update_wrapper_1.logUpdate)(table);
996
- pods = undefined;
997
- yield this.unblockAndSleep(0.5);
998
- } while (watch);
999
- });
1000
- }
1001
- /** Mutates canvas */
1002
- renderReplicaStatusRow(replica, canvas) {
1003
- var _a, _b, _c, _d, _e, _f;
1004
- let replicaName = (_b = (_a = replica.metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "unnamed";
1005
- let podHash = ((_c = replica.metadata) === null || _c === void 0 ? void 0 : _c.labels) ? (_d = replica.metadata) === null || _d === void 0 ? void 0 : _d.labels["pod-template-hash"] : undefined;
1006
- let replicaId = podHash ? replicaName.slice(replicaName.indexOf(podHash)) : replicaName;
1007
- let assetVersion = ((_e = replica.metadata) === null || _e === void 0 ? void 0 : _e.labels) ? (_f = replica.metadata) === null || _f === void 0 ? void 0 : _f.labels[codiac_constants_1.CodiacLabels.LABEL_ASSET_VERSION] : undefined;
1008
- // Version separator
1009
- if (assetVersion !== undefined && assetVersion !== canvas.curver) {
1010
- canvas.curver = assetVersion;
1011
- canvas.table = canvas.table.concat(`${assetVersion}`, "\n");
1012
- }
1013
- // Each replica
1014
- if (replica.status) {
1015
- let state = this.renderPodState(replica);
1016
- let condition = this.renderCondition(replica);
1017
- let restarts = (replica.status.containerStatuses && replica.status.containerStatuses.length > 0) ? replica.status.containerStatuses[0].restartCount : 0;
1018
- canvas.table = canvas.table.concat(` ${replicaId}) ${state} ${condition} started (${replica.status.startTime}) ${restarts} restarts\n`); // , deployed (${deployed})`)
1019
- }
1020
- }
1021
- renderCondition(replica) {
1022
- var _a;
1023
- let cond = "";
1024
- if (replica.status) {
1025
- if (((_a = replica.status) === null || _a === void 0 ? void 0 : _a.conditions) && replica.status.conditions.length > 0) {
1026
- let latestCond = _.orderBy(replica.status.conditions, x => x.lastTransitionTime, "desc")[0];
1027
- cond = latestCond.type;
1028
- if (latestCond.reason) {
1029
- cond = cond.concat(" (", latestCond.reason, ")");
1030
- }
1031
- if (latestCond.message) {
1032
- // TODO: Revisit; message is prob too much info to jam into a cli output line.
1033
- cond = cond.concat(" ('", latestCond.message, "')");
1034
- }
1035
- cond = cond.concat(` since (${latestCond.lastTransitionTime})`);
1036
- }
1037
- }
1038
- return cond;
1039
- }
1040
- renderPodState(replica) {
1041
- var _a, _b, _c, _d;
1042
- let state = "[no status found]";
1043
- if ((_a = replica.metadata) === null || _a === void 0 ? void 0 : _a.deletionTimestamp) {
1044
- state = "Terminating";
1045
- }
1046
- else if (replica.status) {
1047
- state = "";
1048
- // Pod phase
1049
- if (replica.status.phase) {
1050
- state = replica.status.phase;
1051
- }
1052
- if (replica.status.reason) {
1053
- state = state.concat(" (", replica.status.reason, ")");
1054
- }
1055
- if (replica.status.message) {
1056
- state = state.concat(" ('", replica.status.message, "')");
1057
- }
1058
- // container state
1059
- if (replica.status.containerStatuses && replica.status.containerStatuses.length > 0) {
1060
- let ctrStatus = replica.status.containerStatuses[0];
1061
- // state = state.concat(" ", JSON.stringify(ctrStatus.state), "\n");
1062
- if ((_b = ctrStatus.state) === null || _b === void 0 ? void 0 : _b.waiting) {
1063
- if (ctrStatus.state.waiting.reason) {
1064
- state = state.concat(" (", ctrStatus.state.waiting.reason, ")");
1065
- }
1066
- if (ctrStatus.state.waiting.message) {
1067
- state = state.concat(" ('", ctrStatus.state.waiting.message, "')");
1068
- }
1069
- }
1070
- else if ((_c = ctrStatus.state) === null || _c === void 0 ? void 0 : _c.terminated) {
1071
- if (ctrStatus.state.terminated.reason) {
1072
- state = state.concat(" (", ctrStatus.state.terminated.reason, ")");
1073
- }
1074
- if (ctrStatus.state.terminated.message) {
1075
- state = state.concat(" (", ctrStatus.state.terminated.message, ")");
1076
- }
1077
- }
1078
- else if ((_d = ctrStatus.state) === null || _d === void 0 ? void 0 : _d.running) {
1079
- }
1080
- }
1081
- }
1082
- return state;
1083
- }
1084
- unblockAndSleep(durationInSecs) {
1085
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
1086
- return new Promise(resolve => {
1087
- setTimeout(() => resolve(), durationInSecs * 1000);
1088
- });
1089
- });
1090
- }
1091
- /** Fetches pods if not already provided. */
1092
- showStatus(context, namespace, replicas, k8sApi) {
1093
- var _a, _b, _c;
1094
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
1095
- try {
1096
- let k8sClient = k8sApi !== null && k8sApi !== void 0 ? k8sApi : yield this.getK8sClient(context);
1097
- let pods = replicas !== null && replicas !== void 0 ? replicas : yield this.fetchReplicas(context, namespace, k8sClient);
1098
- if (pods && pods.length > 0) {
1099
- // let deployed = res.successes[0].currentVersion.deployed;
1100
- console.log(`Status for ${context.asset} ${(pods.length > 0) ? " instances" : ""} running in ${context.environment}/${context.cabinet}`);
1101
- for (let replica of pods) {
1102
- let replicaName = (_b = (_a = replica.metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "unnamed";
1103
- if (((_c = replica.status) === null || _c === void 0 ? void 0 : _c.conditions) && replica.status.conditions.length > 0) {
1104
- let latestCond = _.orderBy(replica.status.conditions, x => x.lastTransitionTime, "desc")[0];
1105
- console.log(`${replicaName} ${latestCond.type} since (${latestCond.lastTransitionTime}) started (${replica.status.startTime}) ${replica.status.containerStatuses[0].restartCount} restarts`); // , deployed (${deployed})`)
1106
- }
1107
- else {
1108
- console.log("Condition not available"); // Thanks, nice and ambiguous; lets give them something actionable here instead.
1109
- }
1110
- }
1111
- }
1112
- else {
1113
- this._ui.userMessage(`No running instances found.`);
1114
- }
1115
- return;
1116
- }
1117
- catch (err) {
1118
- throw err;
1119
- }
1120
- });
1121
- }
1122
- showLogs(context, logOptions) {
1123
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
1124
- try {
1125
- // SHOW LOGS
1126
- let req = Object.assign(Object.assign({}, context), { logOptions: logOptions });
1127
- let cnxnResult = yield this.genRelayClient.Call.getLogStreamSpecs(req);
1128
- if (cnxnResult.error)
1129
- throw cnxnResult.error;
1130
- if (cnxnResult.output == undefined)
1131
- throw new Error(`Failed without error getting log stream connection specs.`);
1132
- const logStream = new stream.PassThrough();
1133
- logStream.on("data", (chunk) => {
1134
- // use write rather than console.log to prevent double line feed
1135
- process.stdout.write(chunk);
1136
- });
1137
- let streamer = new LogStreamer(this.logger);
1138
- let requestOptions = cnxnResult.output;
1139
- // Deserialize from strings into Buffers after their trip over the wire
1140
- if (cnxnResult.output.ca)
1141
- requestOptions.ca = Buffer.from(cnxnResult.output.ca);
1142
- else
1143
- this.logger.warn(`Cluster connection specs retrieved for log streaming did not have a ca.`);
1144
- if (cnxnResult.output.cert)
1145
- requestOptions.cert = Buffer.from(cnxnResult.output.cert);
1146
- else
1147
- this.logger.warn(`Cluster connection specs retrieved for log streaming did not have a cert.`);
1148
- if (cnxnResult.output.key)
1149
- requestOptions.key = Buffer.from(cnxnResult.output.key);
1150
- else
1151
- this.logger.warn(`Cluster connection specs retrieved for log streaming did not have a key.`);
1152
- streamer.go(requestOptions, logStream); // shouldn't we be awaiting this?
1153
- }
1154
- catch (err) {
1155
- throw err;
1156
- }
1157
- });
1158
- }
1159
- /**
1160
- * @param context Fully qualified path, in terms of Codiac entities, to identify a single replica of an asset in a cabinet.
1161
- * @param execArgs Parameters identifying the ultimate command to run and the console behavior.
1162
- * @param K8sEntities The identifying names of the relevant kubernetes objects, corresponding to the asset replica context, that fully qualify the desired container. */
1163
- runExec(context, execArgs, k8sEntities) {
1164
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
1165
- try {
1166
- let k8sCnxnResult = yield this.genRelayClient.Call.getClusterConnectionSpecs(context);
1167
- if (k8sCnxnResult.error)
1168
- throw k8sCnxnResult.error;
1169
- if (k8sCnxnResult.output === undefined || _.isEmpty(k8sCnxnResult.output))
1170
- throw new Error(`Retrieval of cluster connection spec failed without error.`);
1171
- let spec = k8sCnxnResult.output;
1172
- let kc = new k8s.KubeConfig();
1173
- kc.loadFromString(spec);
1174
- // ======================================================================================================
1175
- // We have to resume here because the console keystrokes are not getting through,
1176
- // even though a POC running just the exec (without all the other ui code we're running)
1177
- // doesnt have the input problem.
1178
- //
1179
- // TODO: Find out why we need this stdin resumed.
1180
- // Most likely because it was piped into an spawned child process that has since ended.
1181
- //
1182
- process.stdin.resume(); // Somehwere we probably lost track of a stdin
1183
- //
1184
- //
1185
- // ======================================================================================================
1186
- const exec = new k8s.Exec(kc);
1187
- const ws = yield exec.exec(k8sEntities.namespace, k8sEntities.pod, k8sEntities.container, execArgs.command, process.stdout, process.stderr, process.stdin, execArgs.tty, (status) => {
1188
- // tslint:disable-next-line:no-console
1189
- // console.log("Exited with status:");
1190
- // // tslint:disable-next-line:no-console
1191
- this.logger.debug(`Executed terminal cmd. Status: ${status.status} ${status.reason}`, JSON.stringify(status, null, 2));
1192
- });
1193
- ws.onopen = function open() {
1194
- process.stdout.write("connected");
1195
- };
1196
- ws.onclose = function close(evt) {
1197
- // process.stdout.write("disconnected");
1198
- process.exit(evt.code);
1199
- return;
1200
- };
1201
- ws.onmessage = this.routeK8sWebSocketMessage;
1202
- // function incoming(msg: any) {
1203
- // let buf = Buffer.from(msg.data);
1204
- // // The k8s client prefixes the buffer with the stream number at position 0...
1205
- // let streamNumBuf = buf.readInt8();
1206
- // let payload = buf.toString('utf8', 1); // <-- start at pos 1 to skip the stream number.
1207
- // switch (streamNumBuf) {
1208
- // case WebSocketHandler.StdoutStream /* 1 */:
1209
- // process.stdout.write(payload);
1210
- // break;
1211
- // case WebSocketHandler.StderrStream /* 2 */:
1212
- // process.stderr.write(`ERROR: ` + payload);
1213
- // break;
1214
- // case WebSocketHandler.StatusStream /* 3 */:
1215
- // let k8sStatus = JSON.parse(payload) as V1Status;
1216
- // process.stdout.write(`STATUS: ${k8sStatus.status}: ${k8sStatus.message}`);
1217
- // break;
1218
- // default:
1219
- // process.stderr.write(`feedback on ${streamNumBuf}`)
1220
- // }
1221
- // return;
1222
- // };
1223
- // This never gets hit. Instead, onmessage gets hit with a message designated for stderr stream.
1224
- ws.onerror = function error(err) {
1225
- process.stdout.write(`Error: ${err.message}`);
1226
- ws.close();
1227
- };
1228
- // Gotta do a process.exit(code) to give the control back.
1229
- // THese dont fire
1230
- // ws.once('exit', (code) => process.exit(code));
1231
- // ws.once('end', (code) => process.stdout.write("end event fired"));
1232
- return;
1233
- }
1234
- catch (err) {
1235
- throw err;
1236
- }
1237
- });
1238
- }
1239
- /** Parses the stream number from the incoming message,
1240
- * and writes the data to the designated target stream.
1241
- *
1242
- * (The k8s client prefixes the buffer with the stream number at position 0)
1243
- */
1244
- routeK8sWebSocketMessage(msg) {
1245
- var _a;
1246
- let buf = Buffer.from(msg.data);
1247
- // The k8s client prefixes the buffer with the stream number at position 0...
1248
- let streamNumBuf = buf.readInt8();
1249
- let payload = buf.toString('utf8', 1); // <-- start at pos 1 to skip the stream number.
1250
- switch (streamNumBuf) {
1251
- case web_socket_handler_1.WebSocketHandler.StdoutStream /* 1 */:
1252
- process.stdout.write(payload);
1253
- break;
1254
- case web_socket_handler_1.WebSocketHandler.StderrStream /* 2 */:
1255
- process.stderr.write(`ERROR: ` + payload);
1256
- break;
1257
- case web_socket_handler_1.WebSocketHandler.StatusStream /* 3 */:
1258
- let k8sStatus = JSON.parse(payload);
1259
- if (((_a = k8sStatus.status) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === "failure") {
1260
- if (k8sStatus.reason !== "NonZeroExitCode") {
1261
- process.stdout.write(`STATUS: ${k8sStatus.status}: ${k8sStatus.message}`);
1262
- }
1263
- }
1264
- break;
1265
- default:
1266
- process.stderr.write(`feedback on ${streamNumBuf}`);
1267
- }
1268
- return;
1269
- }
1270
- }
1271
- exports.default = AssetView;
1272
- AssetView.description = 'Renders a selected type of content for an asset';
1273
- AssetView.aliases = ['asset:monitor', "asset:mon", "asset:get"];
1274
- AssetView.flags = {
1275
- help: core_1.Flags.help({ char: 'h' }),
1276
- enterprise: core_1.Flags.string({ char: 'e', description: 'The name of the enterprise containing the asset being viewed.' }),
1277
- asset: core_1.Flags.string({ char: 'a', description: 'The name of the asset to view.' }),
1278
- environment: core_1.Flags.string({ char: 'n', description: 'The name of the environment in which the cabinet resides.' }),
1279
- cabinet: core_1.Flags.string({ char: 'c', description: 'The name of the cabinet from which the content is to be drawn.' }),
1280
- replica: core_1.Flags.string({ char: 'r', description: 'The name of one of the asset instances currently running in the cabinet.' }),
1281
- type: core_1.Flags.string({ char: 't', options: [...Object.keys(AssetContentType)], description: 'The type of content to retrieve.' }),
1282
- terminal: core_1.Flags.string({ options: ["bash", "sh"], description: 'Command used to start the terminal (defaults to "bash")' }),
1283
- logsFollow: core_1.Flags.boolean({ char: 'f', default: false, description: '(requires type=logs) Follow (aka watch, tail, stream) the output.' }),
1284
- logsTail: core_1.Flags.integer({ char: 'l', default: 10, description: '(requires type=logs) Lines of recent logs to include in the output. Enter -1 to include the entire log history stored in the container.' }),
1285
- configFile: core_1.Flags.string({ char: 'F', description: '(requires type=config) The root pathname to the config file to fetch.' }),
1286
- silent: core_1.Flags.boolean({ exclusive: ["echo", "toscript"], description: 'Non-Interactive mode; executes without any user interaction and fails on any missing or invalid arguments.' }),
1287
- echo: core_1.Flags.boolean({ exclusive: ["toscript", "silent"], description: 'Echo interaction mode; renders the equivalent non-interactive cli command for future use before final execution.' }),
1288
- toscript: core_1.Flags.boolean({ exclusive: ["echo", "silent"], description: 'Toscript interaction mode; renders the equivalent non-interactive cli command WITHOUT any execution.' }),
1289
- takeDefaults: core_1.Flags.boolean({ exclusive: ["silent"], description: "Prevents prompting for confirmation on parameters that were passed in or were set to default values." })
1290
- // tty: Flags.boolean({ char: 'i', default: false, description: '(requires type=exec) Specifies an interactive console session.' })
1291
- };
1292
- AssetView.strict = false; // disables argument validation so we can support variable-length arguments.
1293
- AssetView.args = {
1294
- cmd: core_1.Args.string({ description: '(requires type=exec) command and its space-separated arguments to run in the target replica.' })
1295
- };
1296
- class ExecArgs {
1297
- constructor(command, tty = true) {
1298
- this.command = command;
1299
- this.tty = tty;
1300
- }
1301
- }
1302
- exports.ExecArgs = ExecArgs;
1303
- class ConfigFileArgs {
1304
- constructor(rootPathName) {
1305
- this.rootPathName = rootPathName;
1306
- }
1307
- }
1308
- exports.ConfigFileArgs = ConfigFileArgs;
1309
- class TermArgs {
1310
- /**
1311
- *
1312
- * @param terminalStartup The type of terminal to open. This command may change depending on what terminal or command shell types are available in the image.
1313
- */
1314
- constructor(terminalStartup) {
1315
- this.terminalStartup = terminalStartup;
1316
- }
1317
- }
1318
- exports.TermArgs = TermArgs;
1319
- /** Idnetifies a container, in a pod, in a namespace, in a cluster. */
1320
- class K8sContainerRef {
1321
- constructor(namespace, podName,
1322
- /** This should be optional. When there's only one container in a pod,
1323
- * we should be able to derive this from the pod spec. */
1324
- containerName) {
1325
- this.namespace = namespace;
1326
- this.podName = podName;
1327
- this.containerName = containerName;
1328
- }
1329
- }
1330
- exports.K8sContainerRef = K8sContainerRef;
1331
- class LogStreamer {
1332
- constructor(logger) {
1333
- this.logger = logger;
1334
- }
1335
- go(requestOptions, stream) {
1336
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
1337
- return new Promise((resolve, reject) => {
1338
- const req = request(requestOptions, (error, response, body) => {
1339
- if (error) {
1340
- reject(error);
1341
- }
1342
- else if (response.statusCode !== 200) {
1343
- this.logger.detail(`Error connecting to log stream`, body);
1344
- let details;
1345
- try {
1346
- const k8sStatus = client_node_1.ObjectSerializer.deserialize(JSON.parse(body), 'V1Status');
1347
- details = `${k8sStatus.status}${k8sStatus.reason ? " (" + k8sStatus.reason + ")" : ""} ${k8sStatus.message}`;
1348
- }
1349
- catch (_a) {
1350
- details = "See cli log for details.";
1351
- }
1352
- reject(new Error(`Error connecting to log stream. ${details}`));
1353
- }
1354
- }).on('response', (response) => {
1355
- if (response.statusCode === 200) {
1356
- req.pipe(stream);
1357
- resolve(req);
1358
- }
1359
- });
1360
- });
1361
- });
1362
- }
1363
- }
1364
- exports.LogStreamer = LogStreamer;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LogStreamer = exports.K8sContainerRef = exports.TermArgs = exports.ConfigFileArgs = exports.ExecArgs = exports.K8S_POD_PHASES = exports.InteractionModes = exports.AssetContentType = exports.PROMPT_ME_DESIGNATOR = void 0;
4
+ const tslib_1 = require("tslib");
5
+ //import * as path from 'path';
6
+ const stream = require("stream");
7
+ const core_1 = require("@oclif/core");
8
+ const _ = require("lodash");
9
+ const SplitCmd = require('split-cmd');
10
+ const request = require("request");
11
+ const semver = require("semver");
12
+ const k8s = require("@kubernetes/client-node");
13
+ const codiac_relay_contracts_1 = require("@codiac.io/codiac-relay-contracts");
14
+ const command_base_enterprise_1 = require("../../command-base-enterprise");
15
+ const render = require("../../uilogic/render-methods");
16
+ const cloud_provider_contextualizer_1 = require("../../uilogic/cloud-provider-contextualizer");
17
+ const client_node_1 = require("@kubernetes/client-node");
18
+ const web_socket_handler_1 = require("@kubernetes/client-node/dist/web-socket-handler");
19
+ const codiac_ops_common_1 = require("@codiac.io/codiac-ops-common");
20
+ // let logUpdate: any;
21
+ // (async function () {
22
+ // logUpdate = (await import("log-update")).default;
23
+ // })()
24
+ // import * as logUpdate from "log-update";
25
+ // import logUpdate from "log-update";
26
+ // const logUpdate = (await import("log-update/index.js")).default
27
+ // import { logUpdate } from "log-update";
28
+ // const logUpdate = require("log-update");
29
+ const log_update_wrapper_1 = require("../../log-update-wrapper");
30
+ const codiac_constants_1 = require("../../codiac-constants");
31
+ // const { selectFiles, COMPLETED, CANCELLED } = require('select-files-cli'); // gd js wo ts...
32
+ // const { selectFiles, COMPLETED, CANCELLED } = require('../../uilogic/file-selector'); // gd js wo ts...
33
+ /** The value provided as input that indicates
34
+ * a user's desire to be prompted with a list from which choose the value(s),
35
+ * instead of entering them manually or taking a default. */
36
+ exports.PROMPT_ME_DESIGNATOR = "?";
37
+ var AssetContentType;
38
+ (function (AssetContentType) {
39
+ AssetContentType["logs"] = "logs";
40
+ AssetContentType["term"] = "term";
41
+ AssetContentType["exec"] = "exec";
42
+ AssetContentType["env"] = "env";
43
+ AssetContentType["config"] = "config";
44
+ AssetContentType["status"] = "status";
45
+ // | "footprint-usage" | "infrx"
46
+ // | "ingress-domains" | "ingress-nslookup" | "ingress-routes" | "ingress-logs" | "ssl-certs" | "ssl-logs" | "ssl-cert-history";
47
+ })(AssetContentType = exports.AssetContentType || (exports.AssetContentType = {}));
48
+ const DEFAULT_TERMINAL_STARTER = "bash";
49
+ /** The quantity of lines of backlog to include in the log output. */
50
+ const DEFAULT_LOG_TAIL = 10;
51
+ var InteractionModes;
52
+ (function (InteractionModes) {
53
+ InteractionModes["echo"] = "echo";
54
+ InteractionModes["toscript"] = "toscript";
55
+ InteractionModes["silent"] = "silent";
56
+ })(InteractionModes = exports.InteractionModes || (exports.InteractionModes = {}));
57
+ /** This belongs to k8s - not us, but @kubernetes/client-node has no enum or constants for these magic strings...
58
+ *
59
+ * @see https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
60
+ */
61
+ var K8S_POD_PHASES;
62
+ (function (K8S_POD_PHASES) {
63
+ K8S_POD_PHASES["Pending"] = "Pending";
64
+ K8S_POD_PHASES["Running"] = "Running";
65
+ K8S_POD_PHASES["Succeeded"] = "Succeeded";
66
+ K8S_POD_PHASES["Failed"] = "Failed";
67
+ K8S_POD_PHASES["Unknown"] = "Unknown";
68
+ })(K8S_POD_PHASES = exports.K8S_POD_PHASES || (exports.K8S_POD_PHASES = {}));
69
+ class AssetView extends command_base_enterprise_1.CommandBaseEnterprise {
70
+ constructor() {
71
+ super(...arguments);
72
+ this.takeDefaults = false;
73
+ }
74
+ get uiCloudPvd() {
75
+ if (this._uiCloudPvd_backer === undefined) {
76
+ this._uiCloudPvd_backer = this.ioc.get(cloud_provider_contextualizer_1.CloudProviderContextualizer);
77
+ }
78
+ return this._uiCloudPvd_backer;
79
+ }
80
+ bootstrap() {
81
+ super.bootstrap();
82
+ cloud_provider_contextualizer_1.CloudProviderContextualizer.bootstrap(this.ioc); // (idempotent) this is a dependency of the configurators
83
+ }
84
+ run() {
85
+ var _a, _b, _c;
86
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
87
+ try {
88
+ // ==================================================
89
+ // 1. Bootstrap
90
+ // ==================================================
91
+ this.bootstrap();
92
+ // this._relayContainer?.ready$
93
+ // .subscribe(async (ready: boolean) => {
94
+ // ==================================================
95
+ // 2. Gather cli input
96
+ // ==================================================
97
+ const { args, flags } = yield this.parse(AssetView);
98
+ const interactionMode = (_b = (_a = (flags.echo ? InteractionModes.echo : undefined)) !== null && _a !== void 0 ? _a : (flags.toscript ? InteractionModes.toscript : undefined)) !== null && _b !== void 0 ? _b : (flags.silent ? InteractionModes.silent : undefined);
99
+ this.takeDefaults = (_c = flags.takeDefaults) !== null && _c !== void 0 ? _c : false;
100
+ let partialReq = {};
101
+ partialReq.enterprise = flags.enterprise;
102
+ partialReq.asset = flags.asset;
103
+ partialReq.environment = flags.environment;
104
+ partialReq.cabinet = flags.cabinet;
105
+ partialReq.content = (flags.type) ? AssetContentType[flags.type] : undefined;
106
+ partialReq.replica = flags.replica;
107
+ let givenCmd;
108
+ if (args.cmd) {
109
+ givenCmd = args.cmd;
110
+ let isep = this.argv.indexOf("--");
111
+ if (isep >= 0) {
112
+ if (isep + 1 < this.argv.length) {
113
+ givenCmd = this.argv.slice(isep + 1);
114
+ }
115
+ else {
116
+ givenCmd = undefined;
117
+ }
118
+ }
119
+ }
120
+ let contentOptions = {
121
+ follow: flags.logsFollow,
122
+ tailLines: flags.logsTail,
123
+ /* tty: flags.tty, */
124
+ command: givenCmd,
125
+ terminalStartup: flags.terminal,
126
+ rootPathName: flags.configFile
127
+ };
128
+ // ==================================================
129
+ // 3. Assemble candidate
130
+ // ==================================================
131
+ let candidate;
132
+ let cmd;
133
+ if (interactionMode == InteractionModes.silent) {
134
+ candidate = yield this.buildCandidate_silently(partialReq, partialReq.content, contentOptions);
135
+ }
136
+ else {
137
+ [candidate, cmd] = yield this.buildCandidate_interactively(partialReq, contentOptions, partialReq.content);
138
+ }
139
+ // ==================================================
140
+ // 4. Render ultimate command string
141
+ // ==================================================
142
+ if (interactionMode == InteractionModes.echo || interactionMode == InteractionModes.toscript) {
143
+ if (cmd && cmd.length > 0) {
144
+ this._ui.userMessage(cmd.join(" "));
145
+ }
146
+ }
147
+ // ==================================================
148
+ // 5. Execute
149
+ // ==================================================
150
+ if (interactionMode != InteractionModes.toscript) {
151
+ yield this.renderSelectedContent(candidate.context, candidate.contentType, candidate.k8sEntities, candidate.contentOptions, candidate.replicas);
152
+ }
153
+ // return;
154
+ // });
155
+ return;
156
+ }
157
+ catch (err) {
158
+ this.handleError(err);
159
+ throw err;
160
+ }
161
+ });
162
+ }
163
+ buildCandidate_silently(partialReq, content, contentOptions) {
164
+ var _a, _b, _c, _d, _e, _f;
165
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
166
+ this.__ui = new codiac_ops_common_1.ThrowingUserInputProvider(this.logger);
167
+ if (content === undefined || _.isEmpty(partialReq.content))
168
+ throw new Error(`No content type specified.`);
169
+ if (partialReq.enterprise === undefined || _.isEmpty(partialReq.enterprise))
170
+ throw new Error(`No enterprise specified.`);
171
+ if (partialReq.asset === undefined || _.isEmpty(partialReq.asset))
172
+ throw new Error(`No asset specified.`);
173
+ if (partialReq.environment === undefined || _.isEmpty(partialReq.environment))
174
+ throw new Error(`No environment specified.`);
175
+ if (partialReq.cabinet === undefined || _.isEmpty(partialReq.cabinet))
176
+ throw new Error(`No cabinet specified.`);
177
+ // Replica should not be required
178
+ // (though this can be confusing when there's more than one;
179
+ // the user will have to know they're only getting a single replica of logs,
180
+ // and they need to know they might have to call out for one.
181
+ // if (partialReq.replica === undefined || _.isEmpty(partialReq.replica)) throw new Error(`No replica specified.`);
182
+ let options;
183
+ switch (partialReq.content) {
184
+ case AssetContentType.logs:
185
+ options = (contentOptions !== null && contentOptions !== void 0 ? contentOptions : {});
186
+ // defaults?
187
+ break;
188
+ case AssetContentType.exec:
189
+ if (_.isEmpty(contentOptions.command))
190
+ throw new Error(`No command specified.`);
191
+ options = {
192
+ command: contentOptions.command,
193
+ tty: (_a = contentOptions.tty) !== null && _a !== void 0 ? _a : false
194
+ };
195
+ break;
196
+ case AssetContentType.config:
197
+ if (_.isEmpty(contentOptions.rootPathName))
198
+ throw new Error(`No file specified.`);
199
+ options = {
200
+ rootPathName: contentOptions.rootPathName
201
+ };
202
+ break;
203
+ case AssetContentType.term:
204
+ options = {
205
+ terminalStartup: (_b = contentOptions.terminalStartup) !== null && _b !== void 0 ? _b : DEFAULT_TERMINAL_STARTER
206
+ };
207
+ break;
208
+ case AssetContentType.env: /* env has no user input */
209
+ default:
210
+ options = {};
211
+ break;
212
+ }
213
+ // Retrieve the list of replicas for the given cabinet.
214
+ let rootMap = yield this.getRootMap(partialReq.enterprise);
215
+ let env = this.deriveEnvironmentFrom(partialReq.enterprise, partialReq.cabinet, rootMap); // this is fkng stupid. Put this value into the cab value
216
+ let cabObj = this.getCabinetInfrx(partialReq.enterprise, env.name, partialReq.cabinet, rootMap);
217
+ if (cabObj.infrx == undefined || _.isEmpty(cabObj.infrx))
218
+ throw new Error(`Cannot connect to cabinet ${cabObj.name}: it has no infrastructure record.`);
219
+ let k8sObj = { namespace: cabObj.infrx.namespace };
220
+ let replicas = yield this.fetchReplicas(partialReq, cabObj.infrx.namespace);
221
+ if (replicas.length > 0) {
222
+ // Set first as default
223
+ partialReq.replica = (_d = (_c = replicas[0].metadata) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : "unnamed";
224
+ k8sObj = {
225
+ namespace: cabObj.infrx.namespace,
226
+ pod: partialReq.replica,
227
+ container: (_f = (_e = replicas[0].spec) === null || _e === void 0 ? void 0 : _e.containers[0].name) !== null && _f !== void 0 ? _f : "unnamed"
228
+ };
229
+ // Select a replica unless it's an asset-level operation
230
+ if (content !== AssetContentType.status) {
231
+ // This method falls back to first found as default, throws if not enough info is provided
232
+ k8sObj = yield this.promptForReplica(replicas, undefined, partialReq.replica);
233
+ partialReq.replica = k8sObj.pod;
234
+ }
235
+ }
236
+ // Assemble
237
+ let candidate = {
238
+ context: {
239
+ enterprise: partialReq.enterprise,
240
+ environment: partialReq.environment,
241
+ asset: partialReq.asset,
242
+ cabinet: partialReq.cabinet,
243
+ replica: partialReq.replica
244
+ },
245
+ contentType: content,
246
+ contentOptions: options,
247
+ k8sEntities: k8sObj,
248
+ replicas: replicas
249
+ };
250
+ return candidate;
251
+ });
252
+ }
253
+ buildCandidate_interactively(partialReq, contentOptions, content) {
254
+ var _a, _b, _c, _d;
255
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
256
+ this._userCntx = yield this.establishTenantContext(this._userCntx);
257
+ let enterprise = (yield this.establishEnterpriseContext()).enterprise;
258
+ partialReq.enterprise = enterprise.code;
259
+ let rootMap = yield this.getRootMap(enterprise.code);
260
+ let replicas;
261
+ let k8sObj;
262
+ let confirmed = false;
263
+ let optionsArgs = [];
264
+ do {
265
+ // 1. Select Asset
266
+ partialReq.asset = yield this.promptForAsset(enterprise.assets, partialReq.asset);
267
+ // 2. Cabinet
268
+ let cabObj = yield this.promptForCabinet(partialReq.enterprise, rootMap, partialReq.cabinet);
269
+ partialReq.cabinet = cabObj.name;
270
+ partialReq.environment = this.deriveEnvironmentFrom(partialReq.enterprise, partialReq.cabinet, rootMap).name;
271
+ let cluster = this.deriveClusterFrom(partialReq.enterprise, partialReq.environment, partialReq.cabinet, rootMap);
272
+ // partialReq.cabinet = await this.establishCabinetContext(partialReq.cabinet);
273
+ if (cabObj.infrx == undefined || _.isEmpty(cabObj.infrx))
274
+ throw new Error(`Cannot connect to cabinet ${cabObj.name}: it has no infrastructure record.`);
275
+ k8sObj = { namespace: cabObj.infrx.namespace };
276
+ // 3. Content type
277
+ content = yield this.promptForContentType(content);
278
+ // 4. Content-specific arguments
279
+ // MarkStartHere("implement prompt-me designator.")
280
+ // MarkStartHere("Support the current logger or ioc ctr inside the ws event handlers");
281
+ // MarkStartHere("Need UI to operate a different stream than stdout (so piping stdout wont include the ui content");
282
+ [contentOptions, optionsArgs] = yield this.promptForContentOptions(content, partialReq, contentOptions);
283
+ // 5. Authenticate with CSP
284
+ this.uiCloudPvd.takeDefaults = this.takeDefaults;
285
+ yield this.uiCloudPvd.promptForCloudProviderCreds(this.ioc, cluster.provider);
286
+ // 6. Replica (Pod)
287
+ if (cabObj.infrx == undefined || _.isEmpty(cabObj.infrx))
288
+ throw new Error(`Cannot connect to cabinet ${cabObj.name}: it has no infrastructure record.`);
289
+ replicas = yield this.fetchReplicas(partialReq, cabObj.infrx.namespace);
290
+ if (replicas.length > 0) {
291
+ // Set first as default
292
+ partialReq.replica = (_b = (_a = replicas[0].metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "unnamed";
293
+ k8sObj = {
294
+ namespace: cabObj.infrx.namespace,
295
+ pod: partialReq.replica,
296
+ container: (_d = (_c = replicas[0].spec) === null || _c === void 0 ? void 0 : _c.containers[0].name) !== null && _d !== void 0 ? _d : "unnamed"
297
+ };
298
+ // Select a replica unless it's an asset-level operation
299
+ if (content !== AssetContentType.status) {
300
+ k8sObj = yield this.promptForReplica(replicas, undefined, partialReq.replica);
301
+ partialReq.replica = k8sObj.pod;
302
+ }
303
+ }
304
+ // 7. Confirm or loop back around to enterprise
305
+ confirmed = true; // This is a readonly ui (no danger), and we want to enable fast switching among diff content types, so let's not waste time confirming. // await this._ui.promptConfirm("confirm", "Apply? ");
306
+ } while (!confirmed);
307
+ // We're hard-coding instead of casting here to validate at build-time that each partial property is fully-hydrated.
308
+ // Assemble
309
+ let candidate = {
310
+ context: {
311
+ enterprise: partialReq.enterprise,
312
+ environment: partialReq.environment,
313
+ asset: partialReq.asset,
314
+ cabinet: partialReq.cabinet,
315
+ replica: partialReq.replica
316
+ },
317
+ contentType: content,
318
+ contentOptions: contentOptions,
319
+ k8sEntities: k8sObj,
320
+ replicas: replicas
321
+ };
322
+ // Build command string
323
+ let cmd = ["cod", "asset", "view"];
324
+ cmd.push("--silent");
325
+ cmd.push("-e", candidate.context.enterprise);
326
+ cmd.push("-a", candidate.context.asset);
327
+ cmd.push("-n", candidate.context.environment);
328
+ cmd.push("-c", candidate.context.cabinet);
329
+ if (candidate.context.replica)
330
+ cmd.push("-r", candidate.context.replica);
331
+ cmd.push("-t", candidate.contentType);
332
+ cmd.push(...optionsArgs);
333
+ return [candidate, cmd];
334
+ });
335
+ }
336
+ promptForContentOptions(contentType, context, defaults) {
337
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
338
+ let cmdArgs = [];
339
+ try {
340
+ switch (contentType) {
341
+ case AssetContentType.logs:
342
+ let logArgs = yield this.promptForLogOptions(defaults);
343
+ if (logArgs.follow)
344
+ cmdArgs.push("-f");
345
+ if (logArgs.tailLines)
346
+ cmdArgs.push(...["-l", "" + logArgs.tailLines]);
347
+ return [logArgs, cmdArgs];
348
+ case AssetContentType.exec:
349
+ let execArgs = yield this.promptForExecOptions(defaults);
350
+ cmdArgs.push(...execArgs.command);
351
+ return [execArgs, cmdArgs];
352
+ case AssetContentType.config:
353
+ this.enterpriseContextor.takeDefaults = this.takeDefaults;
354
+ let rootPathName = (yield this.enterpriseContextor.promptForTargetFile(context.enterprise, context.asset, defaults === null || defaults === void 0 ? void 0 : defaults.rootPathName));
355
+ let cfgArgs = { rootPathName: rootPathName };
356
+ cmdArgs.push("-F", rootPathName);
357
+ return [cfgArgs, cmdArgs];
358
+ case AssetContentType.term:
359
+ let termArgs = yield this.promptForTerminalOptions(defaults);
360
+ if (termArgs.terminalStartup)
361
+ cmdArgs.push(...["--terminal", termArgs.terminalStartup]);
362
+ return [termArgs, cmdArgs];
363
+ default:
364
+ return [{}, []];
365
+ }
366
+ }
367
+ catch (err) {
368
+ throw err;
369
+ }
370
+ });
371
+ }
372
+ promptForLogOptions(defaults) {
373
+ var _a, _b;
374
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
375
+ let options = (defaults !== null && defaults !== void 0 ? defaults : {});
376
+ options.follow = (_a = options.follow) !== null && _a !== void 0 ? _a : true;
377
+ if (!this.takeDefaults) {
378
+ options.follow = yield this._ui.promptConfirm("follow", "Stream logs? ", options.follow);
379
+ }
380
+ options.tailLines = (_b = options.tailLines) !== null && _b !== void 0 ? _b : DEFAULT_LOG_TAIL;
381
+ if (!this.takeDefaults) {
382
+ options.tailLines = yield this._ui.prompt("tail", "Lines of backlog (-1 for all):", true, options.tailLines);
383
+ }
384
+ return options;
385
+ });
386
+ }
387
+ promptForExecOptions(defaults) {
388
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
389
+ let options = (defaults !== null && defaults !== void 0 ? defaults : {});
390
+ // Command
391
+ let cmdStr;
392
+ let keep = this.takeDefaults;
393
+ if (!_.isEmpty(options.command) && !this.takeDefaults) {
394
+ cmdStr = (typeof options.command === 'string') ? options.command : options.command.join(" ");
395
+ keep = yield this._ui.promptConfirm("keepCommand", `Command: ${this._styler.hilite(cmdStr)} `);
396
+ }
397
+ if (keep && !_.isEmpty(options.command)) {
398
+ // do nothing
399
+ }
400
+ else {
401
+ options.command = (yield this._ui.prompt("command", "Command: ", true, cmdStr));
402
+ options.command = SplitCmd.split(options.command); // no types declarations - f#$&*ing script kiddie.
403
+ // the one above trips on the --output flag in this: kubectl get pods -n cod-zombie-v1 -l assetNamme=codiac-api --output=jsonpath="{.items[*]['metadata.name', 'status.capacity']}"
404
+ // something safer than: options.command = options.command.split(" ");
405
+ }
406
+ return options;
407
+ });
408
+ }
409
+ promptForTerminalOptions(defaults) {
410
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
411
+ let options = (defaults !== null && defaults !== void 0 ? defaults : {});
412
+ // Command
413
+ let keep = this.takeDefaults;
414
+ if (!_.isEmpty(options.terminalStartup) && !this.takeDefaults) {
415
+ keep = yield this._ui.promptConfirm("keepStartup", `Terminal Startup: ${this._styler.hilite(options.terminalStartup)} `);
416
+ }
417
+ if (keep && !_.isEmpty(options.terminalStartup)) {
418
+ // do nothing
419
+ }
420
+ else {
421
+ options.terminalStartup = (yield this._ui.prompt("startup", "Terminal Startup: ", true, options.terminalStartup));
422
+ }
423
+ return options;
424
+ });
425
+ }
426
+ promptForContentType(defaultValue) {
427
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
428
+ try {
429
+ let output;
430
+ let choices = Object.keys(AssetContentType);
431
+ let keep = this.takeDefaults;
432
+ if (defaultValue && choices.find(x => x == defaultValue) && !this.takeDefaults) {
433
+ keep = yield this._ui.promptConfirm("keepType", `Type of content: ${this._styler.hilite(defaultValue)} `);
434
+ }
435
+ if (keep && defaultValue !== undefined) {
436
+ output = defaultValue;
437
+ }
438
+ else {
439
+ output = (yield this._ui.promptSelect("type", "Type of content: ", choices));
440
+ }
441
+ return output;
442
+ }
443
+ catch (err) {
444
+ throw err;
445
+ }
446
+ });
447
+ }
448
+ promptForAsset(assets, defaultValue) {
449
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
450
+ try {
451
+ let output;
452
+ let choices = assets.map(a => { return { name: a.name, value: a.name }; });
453
+ choices = _.orderBy(choices, c => c.name);
454
+ /** If we changed the input they provided, we need their confirmation (whether or not they said takeDefaults) */
455
+ let changedUserInput = false;
456
+ if (choices.length === 1) {
457
+ if (defaultValue != choices[0].value) {
458
+ changedUserInput = !_.isEmpty(defaultValue);
459
+ defaultValue = choices[0].value;
460
+ }
461
+ }
462
+ let keep = this.takeDefaults;
463
+ if (defaultValue && choices.find(x => x.value == defaultValue) && (changedUserInput || !this.takeDefaults)) {
464
+ keep = yield this._ui.promptConfirm("keepAsset", `Asset: ${this._styler.hilite(defaultValue)} `);
465
+ }
466
+ if (keep && defaultValue !== undefined) {
467
+ output = defaultValue;
468
+ }
469
+ else {
470
+ output = (yield this._ui.promptSelect("asset", "Asset: ", choices));
471
+ }
472
+ return output;
473
+ }
474
+ catch (err) {
475
+ throw err;
476
+ }
477
+ });
478
+ }
479
+ promptForCabinet(enterprise, rootMap, defaultValue) {
480
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
481
+ try {
482
+ let output;
483
+ // render cab tree with all lines selectable
484
+ let cabTree = this.buildCabinetTree(rootMap);
485
+ let choices = this.buildSelectChoicesFrom(cabTree);
486
+ // ISSUES:
487
+ // 0. Remove the freaking lines from the selected value.
488
+ // 1. Remember the last cabinet (user's enterprise context).
489
+ // 2. We should only render the cabinets that actually contain a deployment of the asset (or dim the others and loop back if selected)
490
+ // 3. The picklist should render the cluster (provider, name, location)
491
+ // 4. PERHAPS? The version of the asset running in the selected cabinet should get rendered (either in the picklist or after the cab is selected)
492
+ /** If we changed the input they provided, we need their confirmation (whether or not they said takeDefaults) */
493
+ const CAB_PREFIX = "cabinet|";
494
+ let cabChoices = choices.filter(c => c.value.startsWith(CAB_PREFIX));
495
+ let changedUserInput = false;
496
+ if (cabChoices.length === 1) {
497
+ if (defaultValue != cabChoices[0].value.slice(CAB_PREFIX.length)) {
498
+ changedUserInput = !_.isEmpty(defaultValue);
499
+ defaultValue = cabChoices[0].value.slice(CAB_PREFIX.length);
500
+ }
501
+ }
502
+ let keep = this.takeDefaults;
503
+ if (defaultValue && Boolean(choices.find(x => x.value === `${CAB_PREFIX}${defaultValue}`)) && (changedUserInput || !this.takeDefaults)) {
504
+ keep = yield this._ui.promptConfirm("keepCabinet", `Cabinet: ${this._styler.hilite(defaultValue)} `);
505
+ }
506
+ if (keep && defaultValue !== undefined) {
507
+ output = defaultValue;
508
+ }
509
+ else {
510
+ let scope;
511
+ let target;
512
+ do {
513
+ if (scope === "environment") {
514
+ // we could just filter it down from here...
515
+ }
516
+ let selection = (yield this._ui.promptSelect("cabinet", "Cabinet: ", choices, false, false));
517
+ let parts = selection.split("|");
518
+ scope = parts[0];
519
+ target = parts[1];
520
+ } while (scope !== "cabinet"); // ensure they select a cabinet
521
+ output = target;
522
+ }
523
+ let env = this.deriveEnvironmentFrom(enterprise, output, rootMap); // this is fkng stupid. Put this value into the cab value
524
+ let cabObj = this.getCabinetInfrx(enterprise, env.name, output, rootMap);
525
+ // return output;
526
+ return cabObj;
527
+ }
528
+ catch (err) {
529
+ throw (err);
530
+ }
531
+ });
532
+ }
533
+ deriveEnvironmentFrom(enterprise, cabinet, rootMap) {
534
+ try {
535
+ let ent = rootMap.enterprises.find(e => e.name === enterprise);
536
+ if (ent === undefined)
537
+ throw new Error(`Cannot find environment: did not recognize enterprise [${enterprise}]`);
538
+ let enviro = ent.environments.find(x => x.cabinets.find(c => c.name === cabinet));
539
+ if (enviro === undefined)
540
+ throw new Error(`Cannot find environment: did not recognize cabinet [${cabinet}]`);
541
+ return enviro;
542
+ }
543
+ catch (err) {
544
+ throw err;
545
+ }
546
+ }
547
+ deriveClusterFrom(enterprise, environment, cabinet, rootMap) {
548
+ try {
549
+ let ent = rootMap.enterprises.find(e => e.name === enterprise);
550
+ if (ent === undefined)
551
+ throw new Error(`Cannot find cluster: did not recognize enterprise [${enterprise}]`);
552
+ let enviro = ent.environments.find(x => x.cabinets.find(c => c.name === cabinet));
553
+ if (enviro === undefined)
554
+ throw new Error(`Cannot find cluster: did not recognize cabinet [${cabinet}]`);
555
+ let cabObj = enviro.cabinets.find(c => c.name === cabinet);
556
+ if (cabObj == undefined)
557
+ throw new Error(`Cannot find cluster: did not recognize cabinet [${cabinet}]`);
558
+ if (cabObj.cluster == undefined)
559
+ throw new Error(`Cannot find cluster: cabinet [${cabinet}] does not have a cluster specified.`);
560
+ let cluster = rootMap.clusters.find(c => c.name == cabObj.cluster);
561
+ if (cluster == undefined)
562
+ throw new Error(`Did not recognize cluster [${cabObj.cluster}]`);
563
+ return cluster;
564
+ }
565
+ catch (err) {
566
+ throw err;
567
+ }
568
+ }
569
+ buildSelectChoicesFrom(tree) {
570
+ try {
571
+ let choices = [];
572
+ // the value is no good here - need scope and target both available
573
+ render.renderStringTree(tree, (txt, item) => choices.push({ name: txt, value: item.value }));
574
+ // // This is one way to do it
575
+ // for (let item of tree) {
576
+ //
577
+ // let thisChoice: PromptChoice = { name: item.text, value: item.text };
578
+ // choices.push(thisChoice);
579
+ //
580
+ // if (item.children && item.children.length > 0) {
581
+ // let children = this.buildSelectChoicesFrom(item.children);
582
+ // choices.push(...children);
583
+ // }
584
+ // }
585
+ return choices;
586
+ }
587
+ catch (err) {
588
+ throw err;
589
+ }
590
+ }
591
+ /** sets each value to "scope|target".
592
+ *
593
+ * This is MOSTLY a COPY-PASTE from the CabinetList command!!! This view is prob gonna be pretty common - consider promoting it to a shared utility. */
594
+ buildCabinetTree(rootMap, existings) {
595
+ var _a, _b, _c, _d;
596
+ let tree = [];
597
+ for (let ent of rootMap.enterprises) {
598
+ let entBranch = { text: `${ent.name} enterprise:`, value: `${codiac_relay_contracts_1.ScopeLevel.enterprise}|${ent.name}` };
599
+ let entSetting = existings === null || existings === void 0 ? void 0 : existings.find(s => s.scope === codiac_relay_contracts_1.ScopeLevel.enterprise && s.target === ent.name);
600
+ if (entSetting !== undefined) {
601
+ let valueSuffix = this.ellipsis(35, (_a = entSetting.value) !== null && _a !== void 0 ? _a : "[set to undefined]");
602
+ valueSuffix = `(${valueSuffix})`;
603
+ entBranch.text = entBranch.text.concat(" ", this._styler.dim(valueSuffix));
604
+ }
605
+ for (let env of _.sortBy(ent.environments, e => e.sequence, e => e.name)) {
606
+ let envBranch = { text: `${env.name}`, value: `${codiac_relay_contracts_1.ScopeLevel.environment}|${env.name}` };
607
+ let envSetting = existings === null || existings === void 0 ? void 0 : existings.find(s => s.scope === codiac_relay_contracts_1.ScopeLevel.environment && s.target === env.name);
608
+ if (envSetting !== undefined) {
609
+ let valueSuffix = this.ellipsis(35, (_b = envSetting.value) !== null && _b !== void 0 ? _b : "[set to undefined]");
610
+ valueSuffix = `(${valueSuffix})`;
611
+ envBranch.text = envBranch.text.concat(" ", this._styler.dim(valueSuffix));
612
+ }
613
+ for (let cab of env.cabinets) {
614
+ // let cwg = rootMap.clusters.find(c => c.name === cab.cluster);
615
+ // let clusterDesc = cwg ? ` (${cab.cluster}, ${cwg.provider} ${cwg.locationName})` : "";
616
+ let cabBranch = {
617
+ text: `${cab.name}`,
618
+ value: `${codiac_relay_contracts_1.ScopeLevel.cabinet}|${cab.name}`
619
+ };
620
+ let cabSetting = existings === null || existings === void 0 ? void 0 : existings.find(s => s.scope === codiac_relay_contracts_1.ScopeLevel.cabinet && s.target === cab.name);
621
+ if (cabSetting !== undefined) {
622
+ let valueSuffix = this.ellipsis(35, (_c = cabSetting.value) !== null && _c !== void 0 ? _c : "[set to undefined]");
623
+ valueSuffix = `(${valueSuffix})`;
624
+ cabBranch.text = cabBranch.text.concat(" ", this._styler.dim(valueSuffix));
625
+ }
626
+ if (envBranch.children === undefined)
627
+ envBranch.children = [];
628
+ (_d = envBranch.children) === null || _d === void 0 ? void 0 : _d.push(cabBranch);
629
+ }
630
+ if (entBranch.children === undefined)
631
+ entBranch.children = [];
632
+ entBranch.children.push(envBranch);
633
+ }
634
+ tree.push(entBranch);
635
+ }
636
+ return tree;
637
+ }
638
+ /** Truncates the string to the given length with an ellipses as suffix */
639
+ ellipsis(maxLength, value) {
640
+ let output = value;
641
+ if (output.length > maxLength) {
642
+ let ellipsis = "..."; // Rather use the ellipsis character but String.fromCharCode(133) is returning a problematic character.
643
+ output = output.slice(0, maxLength - 1 - ellipsis.length).concat(ellipsis);
644
+ }
645
+ return output;
646
+ }
647
+ /**
648
+ *
649
+ * @param enterprise
650
+ * @param environment
651
+ * @param cabinet
652
+ * @param asset
653
+ * @param ctrInPod (Optional, defaults to the first one in the spec) The name of the running container (not the image) inside the pod (relevant only when there's more than one).
654
+ * @param defaultValue
655
+ * @returns
656
+ */
657
+ promptForReplica(replicas, ctrInPod, defaultValue) {
658
+ var _a, _b, _c, _d, _e;
659
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
660
+ try {
661
+ let podName;
662
+ // params: enterprise: string, environment: string, cabinet: string, asset: string
663
+ // // Retrieve replicas
664
+ // this._ui.startSpinner(`Fetching ${asset} replicas in ${environment}/${cabinet}...`)
665
+ // let reps = await this.genRelayClient.Call.assetStatus({ assetName: asset, cabinetName: cabinet, enterpriseCode: enterprise, environment: environment });
666
+ // this._ui.stopSpinner((reps.successes) ? `${reps.successes.length} found.` : "failed.")
667
+ // if (reps.error) throw reps.error;
668
+ // if (reps.successes == undefined || reps.successes.length === 0) throw new Error(`No ${asset} replicas exist in cabinet ${environment}/${cabinet}. ${reps.message ?? ""}`);
669
+ //
670
+ // let replicas = reps.successes[0].currentVersion.pods; // <--- HEY!!! Relay shouldnt be exposing raw k8s contracts here - this shd be a codiac contract
671
+ let choices = replicas.filter(r => { var _a; return ((_a = r.metadata) === null || _a === void 0 ? void 0 : _a.name) !== undefined; })
672
+ .map(r => { var _a, _b, _c; return ({ name: `${(_a = r.metadata.name) !== null && _a !== void 0 ? _a : ""} (${(_b = r.status) === null || _b === void 0 ? void 0 : _b.phase})`, value: (_c = r.metadata.name) !== null && _c !== void 0 ? _c : "" }); });
673
+ // Select a replica...
674
+ if (choices.length === 0) {
675
+ this._ui.userMessage(`No replicas found.`);
676
+ podName = "unknown";
677
+ // return undefined; // <--- this is what we should do here.
678
+ }
679
+ else if (choices.length === 1) {
680
+ podName = choices[0].value;
681
+ this._ui.userMessage(`1 replica found: ${this._styler.hilite(podName)}`);
682
+ }
683
+ else {
684
+ let keep = this.takeDefaults;
685
+ if (defaultValue && Boolean(choices.find(x => x.value === defaultValue)) && !this.takeDefaults) {
686
+ keep = yield this._ui.promptConfirm("keepReplica", `Replica: ${this._styler.hilite(defaultValue)} `);
687
+ }
688
+ if (keep && defaultValue !== undefined) {
689
+ podName = defaultValue;
690
+ }
691
+ else {
692
+ podName = (yield this._ui.promptSelect("replica", "Replica...", choices, false, false)); // Assertion operator ok here - we're not allowing undefined options.
693
+ }
694
+ }
695
+ let replica = (replicas.find(r => { var _a; return ((_a = r.metadata) === null || _a === void 0 ? void 0 : _a.name) === podName; })); // Assertion ok: selection was already limited to this list.
696
+ // Select the container inside...
697
+ let containerName;
698
+ if ((((_a = replica.spec) === null || _a === void 0 ? void 0 : _a.containers) == undefined) || (((_b = replica.spec) === null || _b === void 0 ? void 0 : _b.containers.length) === 0))
699
+ throw new Error("No containers are specified in that replica");
700
+ if (!_.isEmpty(ctrInPod)) {
701
+ let found = replica.spec.containers.find(c => c.name === ctrInPod);
702
+ if (!found)
703
+ throw new Error(`Container [${ctrInPod}] not found in that replica`);
704
+ containerName = found.name;
705
+ }
706
+ else {
707
+ containerName = replica.spec.containers[0].name;
708
+ if (((_c = replica.spec) === null || _c === void 0 ? void 0 : _c.containers.length) > 1) {
709
+ // TODO: promptSelect from the list of containers
710
+ this._ui.userMessage(`${(_d = replica.spec) === null || _d === void 0 ? void 0 : _d.containers.length} containers in that replica; selected ${containerName}`);
711
+ }
712
+ }
713
+ let k8sCtr = {
714
+ namespace: (_e = replica.metadata) === null || _e === void 0 ? void 0 : _e.namespace,
715
+ pod: podName,
716
+ container: containerName
717
+ };
718
+ return k8sCtr;
719
+ }
720
+ catch (err) {
721
+ throw err;
722
+ }
723
+ });
724
+ }
725
+ renderSelectedContent(context, contentType, k8sEntities, contentOptions, replicas) {
726
+ var _a;
727
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
728
+ try {
729
+ switch (contentType) {
730
+ case (AssetContentType.logs):
731
+ if (context.replica == undefined)
732
+ throw new Error("No replica selected.");
733
+ if (k8sEntities.pod == undefined || k8sEntities.container == undefined)
734
+ throw new Error("No replica selected.");
735
+ yield this.showLogs(context, contentOptions);
736
+ break;
737
+ case (AssetContentType.term):
738
+ if (context.replica == undefined)
739
+ throw new Error("No replica selected.");
740
+ if (k8sEntities.pod == undefined || k8sEntities.container == undefined)
741
+ throw new Error("No replica selected.");
742
+ let termArgs = { tty: true, command: (_a = contentOptions === null || contentOptions === void 0 ? void 0 : contentOptions.terminalStartup) !== null && _a !== void 0 ? _a : DEFAULT_TERMINAL_STARTER };
743
+ yield this.runExec(context, termArgs, k8sEntities);
744
+ break;
745
+ case (AssetContentType.exec):
746
+ if (context.replica == undefined)
747
+ throw new Error("No replica selected.");
748
+ if (k8sEntities.pod == undefined || k8sEntities.container == undefined)
749
+ throw new Error("No replica selected.");
750
+ let execArgs = contentOptions;
751
+ execArgs.tty = false; // and we want a run-once behavior so the ws closes after the command completes.
752
+ yield this.runExec(context, execArgs, k8sEntities);
753
+ break;
754
+ case (AssetContentType.config):
755
+ if (context.replica == undefined)
756
+ throw new Error("No replica selected.");
757
+ if (k8sEntities.pod == undefined || k8sEntities.container == undefined)
758
+ throw new Error("No replica selected.");
759
+ let cfgInput = contentOptions;
760
+ if (!cfgInput.rootPathName.startsWith("/"))
761
+ cfgInput.rootPathName = "/".concat(cfgInput.rootPathName);
762
+ let cfgExec = { tty: false, command: ["cat", cfgInput.rootPathName] };
763
+ yield this.runExec(context, cfgExec, k8sEntities);
764
+ break;
765
+ case (AssetContentType.env):
766
+ if (context.replica == undefined)
767
+ throw new Error("No replica selected.");
768
+ if (k8sEntities.pod == undefined || k8sEntities.container == undefined)
769
+ throw new Error("No replica selected.");
770
+ let envArgs = { tty: false, command: "env" };
771
+ yield this.runExec(context, envArgs, k8sEntities);
772
+ break;
773
+ case (AssetContentType.status):
774
+ // await this.watchEvents(context, k8sEntities.namespace, replicas);
775
+ yield this.watchStatus_NEW(context, k8sEntities.namespace, replicas);
776
+ // await this.watchStatus(context, k8sEntities.namespace, replicas);
777
+ // await this.watchReplicaSet(context, k8sEntities.namespace);
778
+ // await this.showStatus(context, k8sEntities.namespace, replicas);
779
+ break;
780
+ default:
781
+ this.logger.debug(`Content type ${contentType} is not yet supported.`, [context, contentType, contentOptions]);
782
+ this._ui.userMessage(`Content type ${contentType} is not yet supported.`);
783
+ }
784
+ return;
785
+ }
786
+ catch (err) {
787
+ throw (err);
788
+ }
789
+ });
790
+ }
791
+ getKubeConfig(context) {
792
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
793
+ // Retrieve cluster connection specs
794
+ let res = yield this.genRelayClient.Call.getClusterConnectionSpecs({
795
+ enterprise: context.enterprise,
796
+ environment: context.environment,
797
+ cabinet: context.cabinet
798
+ });
799
+ if (res.error)
800
+ throw res.error;
801
+ if (res.output == undefined || _.isEmpty(res.output)) {
802
+ this.log(`Failed loading cluster spec: ${res.message}.`);
803
+ throw new Error(`Failed loading cluster spec: ${res.message}.`);
804
+ }
805
+ // Create the k8s client
806
+ let k8sConfig = new client_node_1.KubeConfig();
807
+ k8sConfig.loadFromString(res.output);
808
+ return k8sConfig;
809
+ });
810
+ }
811
+ getK8sClient(context, kube) {
812
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
813
+ let k8sConfig = kube !== null && kube !== void 0 ? kube : (yield this.getKubeConfig(context));
814
+ let theirApi = k8sConfig.makeApiClient(k8s.CoreV1Api);
815
+ return theirApi;
816
+ });
817
+ }
818
+ /** Gets the cluster cnxn specs from the relay, then makes the k8s call from the cli.
819
+ *
820
+ * Throws any errors. */
821
+ fetchReplicas(context, namespace, k8sClient) {
822
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
823
+ try {
824
+ let theirApi = k8sClient !== null && k8sClient !== void 0 ? k8sClient : yield this.getK8sClient(context);
825
+ // Fetch from the cluster
826
+ let podResult = yield theirApi.listNamespacedPod(namespace, undefined, undefined, undefined, undefined, `${codiac_constants_1.CodiacLabels.LABEL_ASSET_NAME}=${context.asset}`);
827
+ let replicas = podResult.body.items;
828
+ // let replicas = _.orderBy(podResult.body.items, p => p.metadata?.labels?.assetVersion, 'desc'); // NOTE: this isnt a semantic version sort
829
+ try {
830
+ // Might need a semver.coerce() in here...
831
+ replicas = replicas.sort((a, b) => { var _a, _b, _c, _d, _e, _f; return semver.rcompare((_c = (_b = (_a = a.metadata) === null || _a === void 0 ? void 0 : _a.labels) === null || _b === void 0 ? void 0 : _b.assetVersion) !== null && _c !== void 0 ? _c : "", (_f = (_e = (_d = b.metadata) === null || _d === void 0 ? void 0 : _d.labels) === null || _e === void 0 ? void 0 : _e.assetVersion) !== null && _f !== void 0 ? _f : ""); }); // removes semvers so they can be sorted uniquely
832
+ }
833
+ catch (err) {
834
+ replicas = _.orderBy(replicas, p => { var _a, _b, _c; return (_c = (_b = (_a = p.metadata) === null || _a === void 0 ? void 0 : _a.labels) === null || _b === void 0 ? void 0 : _b.assetVersion) !== null && _c !== void 0 ? _c : ""; }); // TODO: we need this ALSO sorted by replica set (ie: name or labels["pod-template-hash"])
835
+ }
836
+ return replicas;
837
+ }
838
+ catch (err) {
839
+ throw err;
840
+ }
841
+ });
842
+ }
843
+ // protected async watchEvents(context: AssetReplicaContext, namespace: string, replicas?: k8s.V1Pod[] | undefined): Promise<void> {
844
+ // // let selector = `${CodiacLabels.LABEL_ASSET_NAME}=${context.asset}`;
845
+ // let selector = `app=${context.asset}`;
846
+ // let creds = await this.getKubeConfig(context);
847
+ // let k8sClient = creds.makeApiClient(k8s.EventsV1Api);
848
+ // let watcher = new Watch(creds);
849
+ // watcher.watch(
850
+ // '/apis/events.k8s.io/v1/namespaces/{namespace}/events',
851
+ // )
852
+ // let res = await k8sClient.listNamespacedEvent(namespace, undefined, undefined, undefined, undefined, selector,
853
+ // undefined, undefined, undefined, undefined, true, undefined);
854
+ // }
855
+ watchStatus_NEW(context, namespace, replicas) {
856
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
857
+ // let selector = `${CodiacLabels.LABEL_ASSET_NAME}=${context.asset}`;
858
+ let selector = `app=${context.asset}`;
859
+ let kube = yield this.getKubeConfig(context);
860
+ let k8sClient = yield this.getK8sClient(context);
861
+ (0, log_update_wrapper_1.logUpdate)(`Watching ${this._styler.hilite(context.asset)} in ${context.environment}/${context.cabinet}... (ctrl-c to quit)`);
862
+ log_update_wrapper_1.logUpdate.done();
863
+ (0, log_update_wrapper_1.logUpdate)(`...empty...`);
864
+ // This approach DOES return what's different in the cached list,
865
+ // but doesnt stream updates from the cluster - it only runs a first request,
866
+ // meaning you need to call this repeatedly - this looks not fully-baked...?
867
+ let informer = (0, client_node_1.makeInformer)(kube, `/api/v1/namespaces/${namespace}/pods`, () => k8sClient.listNamespacedPod(namespace, undefined, undefined, undefined, undefined, selector)
868
+ // () => k8sClient.listNamespacedPod(namespace, undefined, undefined, undefined, undefined, selector, undefined, undefined, undefined, undefined, true),
869
+ // selector
870
+ );
871
+ // informer.on('add', (obj: k8s.V1Pod) => { console.log(`Added: ${obj.metadata!.name}`); });
872
+ // informer.on('update', (obj: k8s.V1Pod) => { console.log(`Updated: ${obj.metadata!.name}`); });
873
+ informer.on('change', (obj) => {
874
+ // console.log(`Changed: ${obj.metadata!.name}`);
875
+ let canvas = { table: "", curver: "" };
876
+ let replicas = informer.list(namespace);
877
+ if (replicas.length > 0) {
878
+ for (let pod of replicas) {
879
+ this.renderReplicaStatusRow(pod, canvas);
880
+ }
881
+ }
882
+ else {
883
+ canvas.table = "(no instances found)";
884
+ }
885
+ log_update_wrapper_1.logUpdate.clear();
886
+ (0, log_update_wrapper_1.logUpdate)(canvas.table);
887
+ });
888
+ // informer.on('delete', (obj: k8s.V1Pod) => { console.log(`Deleted: ${obj.metadata!.name}`); });
889
+ informer.on('error', (err) => {
890
+ if (err.statusCode === 401) {
891
+ // TODO: reach out to the relay to refresh the user token in the kubeconfig.
892
+ log_update_wrapper_1.logUpdate.clear();
893
+ (0, log_update_wrapper_1.logUpdate)(`Authentication error; please refresh your credentials.`);
894
+ }
895
+ else {
896
+ log_update_wrapper_1.logUpdate.clear();
897
+ console.error(err);
898
+ }
899
+ // Restart informer after 5sec
900
+ setTimeout(() => {
901
+ informer.start();
902
+ }, 5000);
903
+ });
904
+ informer.start();
905
+ // let watch: boolean = true;
906
+ // listNamespacedPod() with "watch" just floats out into space with no return
907
+ // let podResult = await k8sClient.listNamespacedPod(namespace, undefined, undefined, undefined, undefined,
908
+ // `${CodiacLabels.LABEL_ASSET_NAME}=${context.asset}`, undefined, undefined, undefined, undefined, watch);
909
+ // while (podResult) {
910
+ // logUpdate(`${podResult.body.items.length} pods returned`); // Thanks, nice and ambiguous; lets give them something actionable here instead.
911
+ // }
912
+ });
913
+ }
914
+ watchReplicaSet(context, namespace, replicaSets) {
915
+ var _a, _b, _c, _d, _e, _f, _g;
916
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
917
+ let k8sConfig = (yield this.getKubeConfig(context));
918
+ let k8sClient = k8sConfig.makeApiClient(k8s.AppsV1Api);
919
+ // let selector = `${CodiacLabels.LABEL_ASSET_NAME}=${context.asset}`;
920
+ let selector = `app=${context.asset}`;
921
+ let watch = true;
922
+ do {
923
+ let content = "";
924
+ log_update_wrapper_1.logUpdate.clear();
925
+ try {
926
+ let podResult = yield k8sClient.listNamespacedReplicaSet(namespace, undefined, undefined, undefined, undefined, selector);
927
+ let output = podResult.body.items;
928
+ for (let item of output) {
929
+ if (item.status) {
930
+ content = content.concat(`${(_b = (_a = item.metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "unnamed"} ${(_c = item.status.availableReplicas) !== null && _c !== void 0 ? _c : 0}/${item.status.replicas}`, "\n");
931
+ }
932
+ else {
933
+ content = content.concat(`no status for ${(_e = (_d = item.metadata) === null || _d === void 0 ? void 0 : _d.name) !== null && _e !== void 0 ? _e : "unnamed"}`, "\n");
934
+ }
935
+ }
936
+ }
937
+ catch (err) {
938
+ content = content.concat(`Error ${(_f = err.name) !== null && _f !== void 0 ? _f : ""} ${(_g = err.message) !== null && _g !== void 0 ? _g : ""}`, "\n");
939
+ }
940
+ (0, log_update_wrapper_1.logUpdate)(content);
941
+ yield this.unblockAndSleep(0.5);
942
+ } while (watch);
943
+ });
944
+ }
945
+ watchStatus(context, namespace, replicas) {
946
+ var _a, _b, _c, _d, _e, _f, _g;
947
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
948
+ let watch = true;
949
+ let k8sClient = yield this.getK8sClient(context);
950
+ let pods = replicas;
951
+ let spinChars = ["|", "/", "-", "\\"];
952
+ let spinIndex = -1;
953
+ (0, log_update_wrapper_1.logUpdate)(`Status for ${context.asset} in ${context.environment}/${context.cabinet}... (ctrl-c to quit)`);
954
+ log_update_wrapper_1.logUpdate.done();
955
+ do {
956
+ // await this.showStatus(context, namespace, pods, k8sClient);
957
+ spinIndex++;
958
+ if (spinIndex >= spinChars.length)
959
+ spinIndex = 0;
960
+ let spinner = spinChars[spinIndex];
961
+ // TODO: trap failures here and if status currently exists, render the error and leave the existing
962
+ let table = "";
963
+ try {
964
+ pods = pods !== null && pods !== void 0 ? pods : yield this.fetchReplicas(context, namespace, k8sClient);
965
+ if (pods && pods.length > 0) {
966
+ log_update_wrapper_1.logUpdate.clear();
967
+ let curver = ""; // current asset version being listed
968
+ // let deployed = res.successes[0].currentVersion.deployed;
969
+ for (let replica of pods) {
970
+ let replicaName = (_b = (_a = replica.metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "unnamed";
971
+ let podHash = ((_c = replica.metadata) === null || _c === void 0 ? void 0 : _c.labels) ? (_d = replica.metadata) === null || _d === void 0 ? void 0 : _d.labels["pod-template-hash"] : undefined;
972
+ let replicaId = podHash ? replicaName.slice(replicaName.indexOf(podHash)) : replicaName;
973
+ let assetVersion = ((_e = replica.metadata) === null || _e === void 0 ? void 0 : _e.labels) ? (_f = replica.metadata) === null || _f === void 0 ? void 0 : _f.labels[codiac_constants_1.CodiacLabels.LABEL_ASSET_VERSION] : undefined;
974
+ // Version separator
975
+ if (assetVersion !== undefined && assetVersion !== curver) {
976
+ curver = assetVersion;
977
+ table = table.concat(`${spinner} ${assetVersion}`, "\n");
978
+ }
979
+ // Each replica
980
+ if (replica.status) {
981
+ let state = this.renderPodState(replica);
982
+ let condition = this.renderCondition(replica);
983
+ let restarts = (replica.status.containerStatuses && replica.status.containerStatuses.length > 0) ? replica.status.containerStatuses[0].restartCount : 0;
984
+ table = table.concat(` ${replicaId}) ${state} ${condition} started (${replica.status.startTime}) ${restarts} restarts\n`); // , deployed (${deployed})`)
985
+ }
986
+ }
987
+ }
988
+ else {
989
+ table = table.concat(`No running instances found.`);
990
+ }
991
+ }
992
+ catch (err) {
993
+ table = table.concat(`Error refreshing... ${(_g = err.message) !== null && _g !== void 0 ? _g : err.name}\n`);
994
+ }
995
+ (0, log_update_wrapper_1.logUpdate)(table);
996
+ pods = undefined;
997
+ yield this.unblockAndSleep(0.5);
998
+ } while (watch);
999
+ });
1000
+ }
1001
+ /** Mutates canvas */
1002
+ renderReplicaStatusRow(replica, canvas) {
1003
+ var _a, _b, _c, _d, _e, _f;
1004
+ let replicaName = (_b = (_a = replica.metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "unnamed";
1005
+ let podHash = ((_c = replica.metadata) === null || _c === void 0 ? void 0 : _c.labels) ? (_d = replica.metadata) === null || _d === void 0 ? void 0 : _d.labels["pod-template-hash"] : undefined;
1006
+ let replicaId = podHash ? replicaName.slice(replicaName.indexOf(podHash)) : replicaName;
1007
+ let assetVersion = ((_e = replica.metadata) === null || _e === void 0 ? void 0 : _e.labels) ? (_f = replica.metadata) === null || _f === void 0 ? void 0 : _f.labels[codiac_constants_1.CodiacLabels.LABEL_ASSET_VERSION] : undefined;
1008
+ // Version separator
1009
+ if (assetVersion !== undefined && assetVersion !== canvas.curver) {
1010
+ canvas.curver = assetVersion;
1011
+ canvas.table = canvas.table.concat(`${assetVersion}`, "\n");
1012
+ }
1013
+ // Each replica
1014
+ if (replica.status) {
1015
+ let state = this.renderPodState(replica);
1016
+ let condition = this.renderCondition(replica);
1017
+ let restarts = (replica.status.containerStatuses && replica.status.containerStatuses.length > 0) ? replica.status.containerStatuses[0].restartCount : 0;
1018
+ canvas.table = canvas.table.concat(` ${replicaId}) ${state} ${condition} started (${replica.status.startTime}) ${restarts} restarts\n`); // , deployed (${deployed})`)
1019
+ }
1020
+ }
1021
+ renderCondition(replica) {
1022
+ var _a;
1023
+ let cond = "";
1024
+ if (replica.status) {
1025
+ if (((_a = replica.status) === null || _a === void 0 ? void 0 : _a.conditions) && replica.status.conditions.length > 0) {
1026
+ let latestCond = _.orderBy(replica.status.conditions, x => x.lastTransitionTime, "desc")[0];
1027
+ cond = latestCond.type;
1028
+ if (latestCond.reason) {
1029
+ cond = cond.concat(" (", latestCond.reason, ")");
1030
+ }
1031
+ if (latestCond.message) {
1032
+ // TODO: Revisit; message is prob too much info to jam into a cli output line.
1033
+ cond = cond.concat(" ('", latestCond.message, "')");
1034
+ }
1035
+ cond = cond.concat(` since (${latestCond.lastTransitionTime})`);
1036
+ }
1037
+ }
1038
+ return cond;
1039
+ }
1040
+ renderPodState(replica) {
1041
+ var _a, _b, _c, _d;
1042
+ let state = "[no status found]";
1043
+ if ((_a = replica.metadata) === null || _a === void 0 ? void 0 : _a.deletionTimestamp) {
1044
+ state = "Terminating";
1045
+ }
1046
+ else if (replica.status) {
1047
+ state = "";
1048
+ // Pod phase
1049
+ if (replica.status.phase) {
1050
+ state = replica.status.phase;
1051
+ }
1052
+ if (replica.status.reason) {
1053
+ state = state.concat(" (", replica.status.reason, ")");
1054
+ }
1055
+ if (replica.status.message) {
1056
+ state = state.concat(" ('", replica.status.message, "')");
1057
+ }
1058
+ // container state
1059
+ if (replica.status.containerStatuses && replica.status.containerStatuses.length > 0) {
1060
+ let ctrStatus = replica.status.containerStatuses[0];
1061
+ // state = state.concat(" ", JSON.stringify(ctrStatus.state), "\n");
1062
+ if ((_b = ctrStatus.state) === null || _b === void 0 ? void 0 : _b.waiting) {
1063
+ if (ctrStatus.state.waiting.reason) {
1064
+ state = state.concat(" (", ctrStatus.state.waiting.reason, ")");
1065
+ }
1066
+ if (ctrStatus.state.waiting.message) {
1067
+ state = state.concat(" ('", ctrStatus.state.waiting.message, "')");
1068
+ }
1069
+ }
1070
+ else if ((_c = ctrStatus.state) === null || _c === void 0 ? void 0 : _c.terminated) {
1071
+ if (ctrStatus.state.terminated.reason) {
1072
+ state = state.concat(" (", ctrStatus.state.terminated.reason, ")");
1073
+ }
1074
+ if (ctrStatus.state.terminated.message) {
1075
+ state = state.concat(" (", ctrStatus.state.terminated.message, ")");
1076
+ }
1077
+ }
1078
+ else if ((_d = ctrStatus.state) === null || _d === void 0 ? void 0 : _d.running) {
1079
+ }
1080
+ }
1081
+ }
1082
+ return state;
1083
+ }
1084
+ unblockAndSleep(durationInSecs) {
1085
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
1086
+ return new Promise(resolve => {
1087
+ setTimeout(() => resolve(), durationInSecs * 1000);
1088
+ });
1089
+ });
1090
+ }
1091
+ /** Fetches pods if not already provided. */
1092
+ showStatus(context, namespace, replicas, k8sApi) {
1093
+ var _a, _b, _c;
1094
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
1095
+ try {
1096
+ let k8sClient = k8sApi !== null && k8sApi !== void 0 ? k8sApi : yield this.getK8sClient(context);
1097
+ let pods = replicas !== null && replicas !== void 0 ? replicas : yield this.fetchReplicas(context, namespace, k8sClient);
1098
+ if (pods && pods.length > 0) {
1099
+ // let deployed = res.successes[0].currentVersion.deployed;
1100
+ console.log(`Status for ${context.asset} ${(pods.length > 0) ? " instances" : ""} running in ${context.environment}/${context.cabinet}`);
1101
+ for (let replica of pods) {
1102
+ let replicaName = (_b = (_a = replica.metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "unnamed";
1103
+ if (((_c = replica.status) === null || _c === void 0 ? void 0 : _c.conditions) && replica.status.conditions.length > 0) {
1104
+ let latestCond = _.orderBy(replica.status.conditions, x => x.lastTransitionTime, "desc")[0];
1105
+ console.log(`${replicaName} ${latestCond.type} since (${latestCond.lastTransitionTime}) started (${replica.status.startTime}) ${replica.status.containerStatuses[0].restartCount} restarts`); // , deployed (${deployed})`)
1106
+ }
1107
+ else {
1108
+ console.log("Condition not available"); // Thanks, nice and ambiguous; lets give them something actionable here instead.
1109
+ }
1110
+ }
1111
+ }
1112
+ else {
1113
+ this._ui.userMessage(`No running instances found.`);
1114
+ }
1115
+ return;
1116
+ }
1117
+ catch (err) {
1118
+ throw err;
1119
+ }
1120
+ });
1121
+ }
1122
+ showLogs(context, logOptions) {
1123
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
1124
+ try {
1125
+ // SHOW LOGS
1126
+ let req = Object.assign(Object.assign({}, context), { logOptions: logOptions });
1127
+ let cnxnResult = yield this.genRelayClient.Call.getLogStreamSpecs(req);
1128
+ if (cnxnResult.error)
1129
+ throw cnxnResult.error;
1130
+ if (cnxnResult.output == undefined)
1131
+ throw new Error(`Failed without error getting log stream connection specs.`);
1132
+ const logStream = new stream.PassThrough();
1133
+ logStream.on("data", (chunk) => {
1134
+ // use write rather than console.log to prevent double line feed
1135
+ process.stdout.write(chunk);
1136
+ });
1137
+ let streamer = new LogStreamer(this.logger);
1138
+ let requestOptions = cnxnResult.output;
1139
+ // Deserialize from strings into Buffers after their trip over the wire
1140
+ if (cnxnResult.output.ca)
1141
+ requestOptions.ca = Buffer.from(cnxnResult.output.ca);
1142
+ else
1143
+ this.logger.warn(`Cluster connection specs retrieved for log streaming did not have a ca.`);
1144
+ if (cnxnResult.output.cert)
1145
+ requestOptions.cert = Buffer.from(cnxnResult.output.cert);
1146
+ else
1147
+ this.logger.warn(`Cluster connection specs retrieved for log streaming did not have a cert.`);
1148
+ if (cnxnResult.output.key)
1149
+ requestOptions.key = Buffer.from(cnxnResult.output.key);
1150
+ else
1151
+ this.logger.warn(`Cluster connection specs retrieved for log streaming did not have a key.`);
1152
+ streamer.go(requestOptions, logStream); // shouldn't we be awaiting this?
1153
+ }
1154
+ catch (err) {
1155
+ throw err;
1156
+ }
1157
+ });
1158
+ }
1159
+ /**
1160
+ * @param context Fully qualified path, in terms of Codiac entities, to identify a single replica of an asset in a cabinet.
1161
+ * @param execArgs Parameters identifying the ultimate command to run and the console behavior.
1162
+ * @param K8sEntities The identifying names of the relevant kubernetes objects, corresponding to the asset replica context, that fully qualify the desired container. */
1163
+ runExec(context, execArgs, k8sEntities) {
1164
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
1165
+ try {
1166
+ let k8sCnxnResult = yield this.genRelayClient.Call.getClusterConnectionSpecs(context);
1167
+ if (k8sCnxnResult.error)
1168
+ throw k8sCnxnResult.error;
1169
+ if (k8sCnxnResult.output === undefined || _.isEmpty(k8sCnxnResult.output))
1170
+ throw new Error(`Retrieval of cluster connection spec failed without error.`);
1171
+ let spec = k8sCnxnResult.output;
1172
+ let kc = new k8s.KubeConfig();
1173
+ kc.loadFromString(spec);
1174
+ // ======================================================================================================
1175
+ // We have to resume here because the console keystrokes are not getting through,
1176
+ // even though a POC running just the exec (without all the other ui code we're running)
1177
+ // doesnt have the input problem.
1178
+ //
1179
+ // TODO: Find out why we need this stdin resumed.
1180
+ // Most likely because it was piped into an spawned child process that has since ended.
1181
+ //
1182
+ process.stdin.resume(); // Somehwere we probably lost track of a stdin
1183
+ //
1184
+ //
1185
+ // ======================================================================================================
1186
+ const exec = new k8s.Exec(kc);
1187
+ const ws = yield exec.exec(k8sEntities.namespace, k8sEntities.pod, k8sEntities.container, execArgs.command, process.stdout, process.stderr, process.stdin, execArgs.tty, (status) => {
1188
+ // tslint:disable-next-line:no-console
1189
+ // console.log("Exited with status:");
1190
+ // // tslint:disable-next-line:no-console
1191
+ this.logger.debug(`Executed terminal cmd. Status: ${status.status} ${status.reason}`, JSON.stringify(status, null, 2));
1192
+ });
1193
+ ws.onopen = function open() {
1194
+ process.stdout.write("connected");
1195
+ };
1196
+ ws.onclose = function close(evt) {
1197
+ // process.stdout.write("disconnected");
1198
+ process.exit(evt.code);
1199
+ return;
1200
+ };
1201
+ ws.onmessage = this.routeK8sWebSocketMessage;
1202
+ // function incoming(msg: any) {
1203
+ // let buf = Buffer.from(msg.data);
1204
+ // // The k8s client prefixes the buffer with the stream number at position 0...
1205
+ // let streamNumBuf = buf.readInt8();
1206
+ // let payload = buf.toString('utf8', 1); // <-- start at pos 1 to skip the stream number.
1207
+ // switch (streamNumBuf) {
1208
+ // case WebSocketHandler.StdoutStream /* 1 */:
1209
+ // process.stdout.write(payload);
1210
+ // break;
1211
+ // case WebSocketHandler.StderrStream /* 2 */:
1212
+ // process.stderr.write(`ERROR: ` + payload);
1213
+ // break;
1214
+ // case WebSocketHandler.StatusStream /* 3 */:
1215
+ // let k8sStatus = JSON.parse(payload) as V1Status;
1216
+ // process.stdout.write(`STATUS: ${k8sStatus.status}: ${k8sStatus.message}`);
1217
+ // break;
1218
+ // default:
1219
+ // process.stderr.write(`feedback on ${streamNumBuf}`)
1220
+ // }
1221
+ // return;
1222
+ // };
1223
+ // This never gets hit. Instead, onmessage gets hit with a message designated for stderr stream.
1224
+ ws.onerror = function error(err) {
1225
+ process.stdout.write(`Error: ${err.message}`);
1226
+ ws.close();
1227
+ };
1228
+ // Gotta do a process.exit(code) to give the control back.
1229
+ // THese dont fire
1230
+ // ws.once('exit', (code) => process.exit(code));
1231
+ // ws.once('end', (code) => process.stdout.write("end event fired"));
1232
+ return;
1233
+ }
1234
+ catch (err) {
1235
+ throw err;
1236
+ }
1237
+ });
1238
+ }
1239
+ /** Parses the stream number from the incoming message,
1240
+ * and writes the data to the designated target stream.
1241
+ *
1242
+ * (The k8s client prefixes the buffer with the stream number at position 0)
1243
+ */
1244
+ routeK8sWebSocketMessage(msg) {
1245
+ var _a;
1246
+ let buf = Buffer.from(msg.data);
1247
+ // The k8s client prefixes the buffer with the stream number at position 0...
1248
+ let streamNumBuf = buf.readInt8();
1249
+ let payload = buf.toString('utf8', 1); // <-- start at pos 1 to skip the stream number.
1250
+ switch (streamNumBuf) {
1251
+ case web_socket_handler_1.WebSocketHandler.StdoutStream /* 1 */:
1252
+ process.stdout.write(payload);
1253
+ break;
1254
+ case web_socket_handler_1.WebSocketHandler.StderrStream /* 2 */:
1255
+ process.stderr.write(`ERROR: ` + payload);
1256
+ break;
1257
+ case web_socket_handler_1.WebSocketHandler.StatusStream /* 3 */:
1258
+ let k8sStatus = JSON.parse(payload);
1259
+ if (((_a = k8sStatus.status) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === "failure") {
1260
+ if (k8sStatus.reason !== "NonZeroExitCode") {
1261
+ process.stdout.write(`STATUS: ${k8sStatus.status}: ${k8sStatus.message}`);
1262
+ }
1263
+ }
1264
+ break;
1265
+ default:
1266
+ process.stderr.write(`feedback on ${streamNumBuf}`);
1267
+ }
1268
+ return;
1269
+ }
1270
+ }
1271
+ exports.default = AssetView;
1272
+ AssetView.description = 'Renders a selected type of content for an asset';
1273
+ AssetView.aliases = ['asset:monitor', "asset:mon", "asset:get"];
1274
+ AssetView.flags = {
1275
+ help: core_1.Flags.help({ char: 'h' }),
1276
+ enterprise: core_1.Flags.string({ char: 'e', description: 'The name of the enterprise containing the asset being viewed.' }),
1277
+ asset: core_1.Flags.string({ char: 'a', description: 'The name of the asset to view.' }),
1278
+ environment: core_1.Flags.string({ char: 'n', description: 'The name of the environment in which the cabinet resides.' }),
1279
+ cabinet: core_1.Flags.string({ char: 'c', description: 'The name of the cabinet from which the content is to be drawn.' }),
1280
+ replica: core_1.Flags.string({ char: 'r', description: 'The name of one of the asset instances currently running in the cabinet.' }),
1281
+ type: core_1.Flags.string({ char: 't', options: [...Object.keys(AssetContentType)], description: 'The type of content to retrieve.' }),
1282
+ terminal: core_1.Flags.string({ options: ["bash", "sh"], description: 'Command used to start the terminal (defaults to "bash")' }),
1283
+ logsFollow: core_1.Flags.boolean({ char: 'f', default: false, description: '(requires type=logs) Follow (aka watch, tail, stream) the output.' }),
1284
+ logsTail: core_1.Flags.integer({ char: 'l', default: 10, description: '(requires type=logs) Lines of recent logs to include in the output. Enter -1 to include the entire log history stored in the container.' }),
1285
+ configFile: core_1.Flags.string({ char: 'F', description: '(requires type=config) The root pathname to the config file to fetch.' }),
1286
+ silent: core_1.Flags.boolean({ exclusive: ["echo", "toscript"], description: 'Non-Interactive mode; executes without any user interaction and fails on any missing or invalid arguments.' }),
1287
+ echo: core_1.Flags.boolean({ exclusive: ["toscript", "silent"], description: 'Echo interaction mode; renders the equivalent non-interactive cli command for future use before final execution.' }),
1288
+ toscript: core_1.Flags.boolean({ exclusive: ["echo", "silent"], description: 'Toscript interaction mode; renders the equivalent non-interactive cli command WITHOUT any execution.' }),
1289
+ takeDefaults: core_1.Flags.boolean({ exclusive: ["silent"], description: "Prevents prompting for confirmation on parameters that were passed in or were set to default values." })
1290
+ // tty: Flags.boolean({ char: 'i', default: false, description: '(requires type=exec) Specifies an interactive console session.' })
1291
+ };
1292
+ AssetView.strict = false; // disables argument validation so we can support variable-length arguments.
1293
+ AssetView.args = {
1294
+ cmd: core_1.Args.string({ description: '(requires type=exec) command and its space-separated arguments to run in the target replica.' })
1295
+ };
1296
+ class ExecArgs {
1297
+ constructor(command, tty = true) {
1298
+ this.command = command;
1299
+ this.tty = tty;
1300
+ }
1301
+ }
1302
+ exports.ExecArgs = ExecArgs;
1303
+ class ConfigFileArgs {
1304
+ constructor(rootPathName) {
1305
+ this.rootPathName = rootPathName;
1306
+ }
1307
+ }
1308
+ exports.ConfigFileArgs = ConfigFileArgs;
1309
+ class TermArgs {
1310
+ /**
1311
+ *
1312
+ * @param terminalStartup The type of terminal to open. This command may change depending on what terminal or command shell types are available in the image.
1313
+ */
1314
+ constructor(terminalStartup) {
1315
+ this.terminalStartup = terminalStartup;
1316
+ }
1317
+ }
1318
+ exports.TermArgs = TermArgs;
1319
+ /** Idnetifies a container, in a pod, in a namespace, in a cluster. */
1320
+ class K8sContainerRef {
1321
+ constructor(namespace, podName,
1322
+ /** This should be optional. When there's only one container in a pod,
1323
+ * we should be able to derive this from the pod spec. */
1324
+ containerName) {
1325
+ this.namespace = namespace;
1326
+ this.podName = podName;
1327
+ this.containerName = containerName;
1328
+ }
1329
+ }
1330
+ exports.K8sContainerRef = K8sContainerRef;
1331
+ class LogStreamer {
1332
+ constructor(logger) {
1333
+ this.logger = logger;
1334
+ }
1335
+ go(requestOptions, stream) {
1336
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
1337
+ return new Promise((resolve, reject) => {
1338
+ const req = request(requestOptions, (error, response, body) => {
1339
+ if (error) {
1340
+ reject(error);
1341
+ }
1342
+ else if (response.statusCode !== 200) {
1343
+ this.logger.detail(`Error connecting to log stream`, body);
1344
+ let details;
1345
+ try {
1346
+ const k8sStatus = client_node_1.ObjectSerializer.deserialize(JSON.parse(body), 'V1Status');
1347
+ details = `${k8sStatus.status}${k8sStatus.reason ? " (" + k8sStatus.reason + ")" : ""} ${k8sStatus.message}`;
1348
+ }
1349
+ catch (_a) {
1350
+ details = "See cli log for details.";
1351
+ }
1352
+ reject(new Error(`Error connecting to log stream. ${details}`));
1353
+ }
1354
+ }).on('response', (response) => {
1355
+ if (response.statusCode === 200) {
1356
+ req.pipe(stream);
1357
+ resolve(req);
1358
+ }
1359
+ });
1360
+ });
1361
+ });
1362
+ }
1363
+ }
1364
+ exports.LogStreamer = LogStreamer;
1365
1365
  //# sourceMappingURL=view.js.map