🌳
pt0/opencodeF/k8sF/syncGitSshOcWebAI.mjs
5import { syncCodeserv } from "./epSyncAI.mjs"
21export const syncGitSshOcWeb = async (cfg) => {
22 const {
23 repoName, sshHostAlias, sshKeyPath, authorizedPubKeyPaths,
24 codeservHostname, gitName, gitEmail, deployableEps,
25 pvcEncName,
26 ep,
27 gitsshName, gitsshNodePortNo, gitsshSizeGb,
28 codeservName, codeservSizeGb,
29 isThrowawayEp,
30 getLocalRepoPath,
31 } = cfg
33 const gitsshCfg = {repoName, sshHostAlias, sshKeyPath, authorizedPubKeyPaths,
34 ...(gitsshName && {name: gitsshName}),
35 ...(gitsshNodePortNo && {nodePortNo: gitsshNodePortNo}),
36 ...(gitsshSizeGb && {sizeGb: gitsshSizeGb}),
37 }
39 assertDefined(gitsshName, {gitsshName})
40 const gitsshK8sName = gitsshName
41 const codeservCfg = {
42 codeservHostname,
43 gitsshRemoteUrl: `ssh://${sshHostAlias}/home/git/repos/${repoName}.git`,
44 gitsshK8sName,
45 gitName,
46 gitEmail,
47 deployableEps,
48 ...(codeservName && {name: codeservName}),
49 ...(codeservSizeGb && {sizeGb: codeservSizeGb}),
50 ...(isThrowawayEp && {isThrowawayEp}),
51 }
53 const {cluster_name} = getAppCfg()
54 assertDefined(cluster_name, {cluster_name})
55 const action = getAction()
57 // Register setup and setorigin actions for configuring local git
58 const setup = async () => gitsshCtx.run(gitsshCfg, () => setupGitSshLocal({cluster_name}))
59 setup.cliDescript = 'configure ~/.ssh/config and git remote (idempotent)'
60 const setorigin = async () => gitsshCtx.run(gitsshCfg, () => setoriginGitSshLocal())
61 setorigin.cliDescript = 'set origin remote to gitssh URL (idempotent)'
62 // Only register runtests for non-throwaway (throwaway registers its own destructive runtests)
63 const runtestsAction = async () => { await runCodeservRuntests({codeservHostname, ep}) }
64 runtestsAction.cliDescript = 'run healthcheck tests against deployed codeserv'
65 const runtests = isThrowawayEp ? null : runtestsAction
66 availActionsCtx.enterWith({...availActionsCtx.getStore(), setup, setorigin, ...(runtests && {runtests})})
68 if (action === 'setup') {
69 await setup()
70 return
71 }
72 if (action === 'setorigin') {
73 await setorigin()
74 return
75 }
76 if (action === 'runtests' && runtests) {
77 await runtests()
78 return
79 }
81 // Skip log streaming - multiple sequential deploys would block forever
82 const skipGitsshActions = ['help', 'runtests'] // actions that only need codeserv
83 await multiDeployCtx.run({skipStreamLogs: true}, () =>
84 pvcTypeCtx.run({pvcEncName}, async () => {
85 // Skip gitssh for actions that only need codeserv
86 if (!skipGitsshActions.includes(action)) {
87 // Deploy gitssh first (codeserv needs it to clone repo)
88 await gitsshCtx.run(gitsshCfg, k8sGitSsh)
90 // Init bare repo on gitssh after deploy (idempotent, needed before codeserv can clone)
91 const {cluster_name} = getAppCfg()
92 assertDefined(cluster_name, {cluster_name})
93 if (action === 'apply') {
94 // Update SSH config before any git operations (handles LAN changes)
95 await gitsshCtx.run(gitsshCfg, () => setupGitSshLocal({cluster_name}))
96 await gitsshCtx.run(gitsshCfg, () => initGitsshRepo({cluster_name}))
97 if (getLocalRepoPath) await gitsshCtx.run(gitsshCfg, async () => pushLocalRepoToGitssh({localRepoPath: await getLocalRepoPath(), cluster_name}))
98 }
99 }
101 // Deploy codeserv
102 await codeservCtx.run(codeservCfg, syncCodeserv)
103 })
104 )
107/**
108 * Throwaway codeserv+gitssh deployment for testing.
109 * Handles action dispatch, runtests/testdeploy registration, and hostname derivation.
110 */
111export const eptThrowawayOcWeb = async ({klusterCfg, ep, wcDomain, testGitsshName = 'test-gitssh', testCodeservName = 'test-codeserv', testCodeservHostname: testCodeservHostnameArg, gitsshNodePortNo = 30023, gitsshSizeGb = 1, codeservSizeGb = 3, getLocalRepoPath, ...syncCfg}) => {
112 enterKlusterCtxs(klusterCfg)
113 const testCodeservHostname = testCodeservHostnameArg || await getDerivedHostname({name: testCodeservName, wcDomain})
115 const gitsshCfg = {
116 repoName: syncCfg.repoName,
117 sshHostAlias: syncCfg.sshHostAlias,
118 sshKeyPath: syncCfg.sshKeyPath,
119 authorizedPubKeyPaths: syncCfg.authorizedPubKeyPaths,
120 name: testGitsshName,
121 nodePortNo: gitsshNodePortNo,
122 sizeGb: gitsshSizeGb,
123 }
125 const syncWithAction = async (actionOverride) => {
126 actionCtx.enterWith({action: actionOverride}) // ctx:clear
127 enterKlusterCtxs({...klusterCfg, action: actionOverride})
128 await cliValidatedCtx.run({validated: true}, () => syncGitSshOcWeb({
129 ...syncCfg,
130 codeservHostname: testCodeservHostname,
131 gitsshName: testGitsshName,
132 gitsshNodePortNo,
133 gitsshSizeGb,
134 codeservName: testCodeservName,
135 codeservSizeGb,
136 isThrowawayEp: true,
137 getLocalRepoPath,
138 }))
139 }
141 const setupFn = async () => {
142 try {
143 await gitsshCtx.run(gitsshCfg, () => setupGitSshLocal({cluster_name: klusterCfg.cluster_name}))
144 return {passed: true, msg: 'SSH config setup completed'}
145 } catch (err) {
146 return {passed: false, msg: `setup failed: ${err}`}
147 }
148 }
150 const getPassword = () => getPlainSecOpt(tsSec(`${testCodeservName}-oc-password`))
152 const runtests = async () => runThrowawayCsTests({syncWithAction, cluster_name: klusterCfg.cluster_name, codeservName: testCodeservName, gitsshName: testGitsshName, codeservHostname: testCodeservHostname, ep, setupFn, password: getPassword()})
153 runtests.cliDescript = 'delete + delpvcs + apply throwaway codeserv+gitssh, verify, cleanup'
154 runtests.cliSchema = baseRuntestsCli
156 const testdeploy = async () => runThrowawayCsTests({syncWithAction, cluster_name: klusterCfg.cluster_name, codeservName: testCodeservName, gitsshName: testGitsshName, codeservHostname: testCodeservHostname, ep, setupFn, includeCleanup: false, password: getPassword()})
157 testdeploy.cliDescript = 'delete + delpvcs + apply throwaway codeserv+gitssh, verify (no cleanup)'
158 testdeploy.cliSchema = baseRuntestsCli
160 const customActions = {runtests, testdeploy}
161 availActionsCtx.enterWith({...availActionsCtx.getStore(), ...customActions})
163 const action = getAction()
164 if (!action || action === 'help') {
165 const allActions = {...availActionsCtx.getStore(), ...customActions}
166 return cliBase({actionNames: Object.keys(allActions), actionsH: allActions})
167 }
168 const customAction = customActions[action]
169 if (customAction) {
170 exitOnUnknownArgs(customAction)
171 await customAction()
172 } else {
173 await syncWithAction(action)
174 }