Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/api/v1/cloudtty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const connectCloudtty = async (req: OpenApiRequestExt, res: Response): Pr
export const deleteCloudtty = async (req: OpenApiRequestExt, res: Response): Promise<void> => {
const sessionUser = req.user
debug(`deleteCloudtty - ${sessionUser.email} - ${sessionUser.sub}`)
await req.otomi.deleteCloudtty(sessionUser)
const { teamId } = req.query as { teamId: string }
await req.otomi.deleteCloudtty(teamId, sessionUser)
res.json({})
}
3 changes: 2 additions & 1 deletion src/api/v2/cloudtty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const connectAplCloudtty = async (req: OpenApiRequestExt, res: Response):
export const deleteAplCloudtty = async (req: OpenApiRequestExt, res: Response): Promise<void> => {
const sessionUser = req.user
debug(`deleteCloudtty - ${sessionUser.email} - ${sessionUser.sub}`)
await req.otomi.deleteCloudtty(sessionUser)
const { teamId } = req.query as { teamId: string }
await req.otomi.deleteCloudtty(teamId, sessionUser)
res.json({})
}
34 changes: 12 additions & 22 deletions src/k8s_operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,34 +101,24 @@ export async function checkPodExists(namespace: string, podName: string): Promis
}
}

export async function k8sdelete({
sub,
isPlatformAdmin,
userTeams,
}: {
sub: string
isPlatformAdmin: boolean
userTeams: string[]
}): Promise<void> {
export async function k8sdelete(
namespace: string,
sub: string,
isPlatformAdmin: boolean,
userTeams: string[],
): Promise<void> {
const kc = new KubeConfig()
kc.loadFromDefault()
const k8sApi = kc.makeApiClient(CoreV1Api)
const customObjectsApi = kc.makeApiClient(CustomObjectsApi)
const rbacAuthorizationV1Api = kc.makeApiClient(RbacAuthorizationV1Api)
const resourceName = sub
const namespace = 'team-admin'
try {
const apiVersion = 'v1beta1'
const apiGroupAuthz = 'security.istio.io'
const apiGroupVS = 'networking.istio.io'
const pluralAuth = 'authorizationpolicies'
const pluralVS = 'virtualservices'

await customObjectsApi.deleteNamespacedCustomObject({
group: apiGroupAuthz,
version: apiVersion,
group: 'security.istio.io',
version: 'v1beta1',
namespace,
plural: pluralAuth,
plural: 'authorizationpolicies',
name: `tty-${resourceName}`,
})

Expand All @@ -147,10 +137,10 @@ export async function k8sdelete({
await k8sApi.deleteNamespacedService({ name: `tty-${resourceName}`, namespace })

await customObjectsApi.deleteNamespacedCustomObject({
group: apiGroupVS,
version: apiVersion,
group: 'gateway.networking.k8s.io',
version: 'v1',
namespace,
plural: pluralVS,
plural: 'httproutes',
name: `tty-${resourceName}`,
})
} catch (error) {
Expand Down
19 changes: 11 additions & 8 deletions src/otomi-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1522,6 +1522,8 @@ export default class OtomiStack {
}

async connectCloudtty(teamId: string, sessionUser: SessionUser): Promise<Cloudtty> {
const isAdmin = sessionUser.isPlatformAdmin
const targetNamespace = isAdmin ? 'team-admin' : `team-${teamId}`
if (!sessionUser.sub) {
debug('No user sub found, cannot connect to shell.')
throw new OtomiError(500, 'No user sub found, cannot connect to shell.')
Expand All @@ -1543,14 +1545,14 @@ export default class OtomiStack {
}

// if cloudtty shell does not exists then check if the pod is running and return it
if (await checkPodExists('team-admin', `tty-${sessionUser.sub}`)) {
if (await checkPodExists(targetNamespace, `tty-${sessionUser.sub}`)) {
return { iFrameUrl: `https://tty.${variables.FQDN}/${sessionUser.sub}` }
}

if (await pathExists('/tmp/ttyd.yaml')) await unlink('/tmp/ttyd.yaml')

//if user is admin then read the manifests from ./dist/src/ttyManifests/adminTtyManifests
const files = sessionUser.isPlatformAdmin
const files = isAdmin
? await readdir('./dist/src/ttyManifests/adminTtyManifests', 'utf-8')
: await readdir('./dist/src/ttyManifests', 'utf-8')
const filteredFiles = files.filter((file) => file.startsWith('tty'))
Expand Down Expand Up @@ -1590,15 +1592,15 @@ export default class OtomiStack {
)
await writeFile('/tmp/ttyd.yaml', fileContents, 'utf-8')
await apply('/tmp/ttyd.yaml')
await watchPodUntilRunning('team-admin', `tty-${sessionUser.sub}`)
await watchPodUntilRunning(targetNamespace, `tty-${sessionUser.sub}`)

// check the pod every 30 minutes and terminate it after 2 hours of inactivity
const ISACTIVE_INTERVAL = 30 * 60 * 1000
const TERMINATE_TIMEOUT = 2 * 60 * 60 * 1000
const intervalId = setInterval(() => {
getCloudttyActiveTime('team-admin', `tty-${sessionUser.sub}`).then((activeTime: number) => {
getCloudttyActiveTime(targetNamespace, `tty-${sessionUser.sub}`).then((activeTime: number) => {
if (activeTime > TERMINATE_TIMEOUT) {
this.deleteCloudtty(sessionUser)
this.deleteCloudtty(teamId, sessionUser)
clearInterval(intervalId)
debug(`Cloudtty terminated after ${TERMINATE_TIMEOUT / (60 * 60 * 1000)} hours of inactivity`)
}
Expand All @@ -1608,12 +1610,13 @@ export default class OtomiStack {
return { iFrameUrl: `https://tty.${variables.FQDN}/${sessionUser.sub}` }
}

async deleteCloudtty(sessionUser: SessionUser): Promise<void> {
async deleteCloudtty(teamId: string, sessionUser: SessionUser): Promise<void> {
const { sub, isPlatformAdmin, teams } = sessionUser as { sub: string; isPlatformAdmin: boolean; teams: string[] }
const namespace = isPlatformAdmin ? 'team-admin' : `team-${teamId}`
const userTeams = teams.map((teamName) => `team-${teamName}`)
try {
if (await checkPodExists('team-admin', `tty-${sessionUser.sub}`)) {
await k8sdelete({ sub, isPlatformAdmin, userTeams })
if (await checkPodExists(namespace, `tty-${sessionUser.sub}`)) {
await k8sdelete(namespace, sub, isPlatformAdmin, userTeams)
}
} catch (error) {
debug('Failed to delete cloudtty')
Expand Down
2 changes: 1 addition & 1 deletion src/ttyManifests/adminTtyManifests/tty_02_Pod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ spec:
cpu: '500m'
env:
- name: NAMESPACE
value: team-$TARGET_TEAM
value: $TARGET_TEAM
securityContext:
allowPrivilegeEscalation: false
capabilities:
Expand Down
32 changes: 32 additions & 0 deletions src/ttyManifests/adminTtyManifests/tty_05_HttpRoute.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: tty-$SUB
namespace: team-admin
spec:
hostnames:
- tty.$FQDN
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: platform
namespace: istio-system
sectionName: https
rules:
- backendRefs:
- group: ""
kind: Service
name: tty-$SUB
port: 8080
weight: 1
matches:
- path:
type: PathPrefix
value: /$SUB
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplaceFullPath
replaceFullPath: /
---
34 changes: 0 additions & 34 deletions src/ttyManifests/adminTtyManifests/tty_05_Vs.yaml

This file was deleted.

3 changes: 1 addition & 2 deletions src/ttyManifests/tty_00_Authz.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: tty-$SUB
namespace: team-admin
namespace: $TARGET_TEAM
spec:
selector:
matchLabels:
Expand All @@ -13,4 +13,3 @@ spec:
- key: request.auth.claims[sub]
values: ['$SUB']
---

3 changes: 1 addition & 2 deletions src/ttyManifests/tty_01_Sa.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ apiVersion: v1
kind: ServiceAccount
metadata:
name: tty-$SUB
namespace: team-admin
namespace: $TARGET_TEAM
---

4 changes: 2 additions & 2 deletions src/ttyManifests/tty_02_Pod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ metadata:
app: tty-$SUB
otomi: tty
name: tty-$SUB
namespace: team-admin
namespace: $TARGET_TEAM
spec:
serviceAccountName: tty-$SUB
securityContext:
Expand All @@ -27,7 +27,7 @@ spec:
cpu: '500m'
env:
- name: NAMESPACE
value: team-$TARGET_TEAM
value: $TARGET_TEAM
securityContext:
allowPrivilegeEscalation: false
capabilities:
Expand Down
3 changes: 1 addition & 2 deletions src/ttyManifests/tty_03_Rolebinding.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,5 @@ roleRef:
subjects:
- kind: ServiceAccount
name: tty-$SUB
namespace: team-admin
namespace: $TARGET_TEAM
---

3 changes: 1 addition & 2 deletions src/ttyManifests/tty_04_Svc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ metadata:
labels:
app: tty-$SUB
name: tty-$SUB
namespace: team-admin
namespace: $TARGET_TEAM
spec:
ports:
- name: 8080-8080
Expand All @@ -15,4 +15,3 @@ spec:
app: tty-$SUB
type: ClusterIP
---

32 changes: 32 additions & 0 deletions src/ttyManifests/tty_05_HttpRoute.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: tty-$SUB
namespace: $TARGET_TEAM
spec:
hostnames:
- tty.$FQDN
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: platform
namespace: istio-system
sectionName: https
rules:
- backendRefs:
- group: ""
kind: Service
name: tty-$SUB
port: 8080
weight: 1
matches:
- path:
type: PathPrefix
value: /$SUB
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplaceFullPath
replaceFullPath: /
---
34 changes: 0 additions & 34 deletions src/ttyManifests/tty_05_Vs.yaml

This file was deleted.

Loading