From 854613d107a183b05163bd29a489f287002a7c47 Mon Sep 17 00:00:00 2001 From: Felipe Gonzalez Date: Thu, 25 Apr 2024 14:41:01 -0300 Subject: [PATCH] fix: Also build socat for ports (#55) * fix: Also build socat for ports * Minor fixes * Minor fixes --- operator/src/backend-with-storage/handlers.ts | 21 ++++++--- operator/src/backend/handlers.ts | 21 ++++++--- operator/src/frontend/handlers.ts | 21 ++++++--- operator/src/services.ts | 6 ++- operator/src/shared/cardano-node-helper.ts | 24 +++++++++- operator/src/shared/dependencies.ts | 15 +++++- operator/src/shared/ports.ts | 47 +++++++++++-------- operator/src/workspaces/handlers.ts | 20 +++++--- package.json | 2 +- 9 files changed, 126 insertions(+), 51 deletions(-) diff --git a/operator/src/backend-with-storage/handlers.ts b/operator/src/backend-with-storage/handlers.ts index c256c25..6d6b1f7 100644 --- a/operator/src/backend-with-storage/handlers.ts +++ b/operator/src/backend-with-storage/handlers.ts @@ -2,7 +2,7 @@ import { V1StatefulSet, V1PersistentVolumeClaim, PatchUtils, V1Container, V1EnvV import { getClients, readProjectUnsecure, Network, namespaceToSlug, DependencyResource, ServicePlugin } from '@demeter-sdk/framework'; import { API_VERSION, API_GROUP, PLURAL, SINGULAR, KIND } from './constants'; import { CustomResource, CustomResourceResponse, BackendWithStorage, StorageClass } from '@demeter-run/workloads-types'; -import { buildEnvVars, cardanoNodeDep, getDependenciesForNetwork, isCardanoNodeEnabled } from '../shared/dependencies'; +import { buildEnvVars, cardanoNodeDep, cardanoNodePort, getDependenciesForNetwork, isCardanoNodeEnabled } from '../shared/dependencies'; import { getComputeDCUPerMin, getNetworkFromAnnotations, @@ -15,8 +15,9 @@ import { workloadVolumes, } from '../shared'; import { checkConfigMapExistsOrCreate, configmap } from '../shared/configmap'; -import { buildSocatContainer } from '../shared/cardano-node-helper'; -import { buildPortEnvVars } from '../shared/ports'; +import { buildSocatContainer, buildSocatContainerForPort } from '../shared/cardano-node-helper'; +import { buildPortEnvVars, getPortsForNetwork } from '../shared/ports'; +import { ServiceInstanceWithStatusAndKind } from '../services'; const tolerations = [ { @@ -56,12 +57,14 @@ export async function handleResource( const network = getNetworkFromAnnotations(spec.annotations) as Network; const deps = await getDependenciesForNetwork(project, network); - const portEnvVars = await buildPortEnvVars(project, network); + const ports = await getPortsForNetwork(project, network); + const portEnvVars = await buildPortEnvVars(ports); const depsEnvVars = await buildEnvVars(deps, network); const envVars = [...depsEnvVars, ...portEnvVars]; const cardanoNode = cardanoNodeDep(deps); + const cardanoNodePortInstance = cardanoNodePort(ports); const volumesList = workloadVolumes(name, !!cardanoNode); - const containerList = containers(spec, envVars, cardanoNode); + const containerList = containers(spec, envVars, cardanoNode, cardanoNodePortInstance); try { await apps.readNamespacedStatefulSet(name, ns); //@TODO sync @@ -342,9 +345,11 @@ function containers( spec: BackendWithStorage.Spec, envVars: V1EnvVar[], cardanoNodeDep: { dependency: DependencyResource; service: ServicePlugin } | null, + cardanoNodePort: ServiceInstanceWithStatusAndKind | null, ): V1Container[] { const args = spec.args ? spec.args.split(' ') : []; const command = spec.command ? spec.command.split(' ') : []; + const volumeMounts: V1VolumeMount[] = [ { name: 'storage', @@ -356,7 +361,7 @@ function containers( }, ]; - if (!!cardanoNodeDep) { + if (!!cardanoNodePort || !!cardanoNodeDep) { volumeMounts.push({ name: 'ipc', mountPath: '/ipc', @@ -376,7 +381,9 @@ function containers( }, ]; - if (!!cardanoNodeDep) { + if (!!cardanoNodePort) { + containers.push(buildSocatContainerForPort(cardanoNodePort)); + } else if (!!cardanoNodeDep) { containers.push(buildSocatContainer(cardanoNodeDep.dependency, cardanoNodeDep.service)); } diff --git a/operator/src/backend/handlers.ts b/operator/src/backend/handlers.ts index 3d0c06a..40d9d29 100644 --- a/operator/src/backend/handlers.ts +++ b/operator/src/backend/handlers.ts @@ -2,11 +2,12 @@ import { PatchUtils, V1Container, V1EnvVar, V1Volume, V1VolumeMount, V1Deploymen import { getClients, readProjectUnsecure, Network, namespaceToSlug, DependencyResource, ServicePlugin } from '@demeter-sdk/framework'; import { API_VERSION, API_GROUP, PLURAL } from './constants'; import { CustomResource, CustomResourceResponse, Backend, Pod, WorkloadStatus } from '@demeter-run/workloads-types'; -import { buildEnvVars, cardanoNodeDep, getDependenciesForNetwork, isCardanoNodeEnabled } from '../shared/dependencies'; +import { buildEnvVars, cardanoNodeDep, cardanoNodePort, getDependenciesForNetwork } from '../shared/dependencies'; import { getComputeDCUPerMin, getDeploymentStatus, getNetworkFromAnnotations, getResourcesFromComputeClass, workloadVolumes } from '../shared'; import { checkConfigMapExistsOrCreate, configmap } from '../shared/configmap'; -import { buildSocatContainer } from '../shared/cardano-node-helper'; -import { buildPortEnvVars } from '../shared/ports'; +import { buildSocatContainer, buildSocatContainerForPort } from '../shared/cardano-node-helper'; +import { buildPortEnvVars, getPortsForNetwork } from '../shared/ports'; +import { ServiceInstanceWithStatusAndKind } from '../services'; const tolerations = [ { @@ -45,12 +46,14 @@ export async function handleResource( const network = getNetworkFromAnnotations(spec.annotations) as Network; const deps = await getDependenciesForNetwork(project, network); - const portEnvVars = await buildPortEnvVars(project, network); + const ports = await getPortsForNetwork(project, network); + const portEnvVars = await buildPortEnvVars(ports); const depsEnvVars = await buildEnvVars(deps, network); const envVars = [...depsEnvVars, ...portEnvVars]; const cardanoNode = cardanoNodeDep(deps); + const cardanoNodePortInstance = cardanoNodePort(ports); const volumesList = workloadVolumes(name, !!cardanoNode); - const containerList = containers(spec, envVars, cardanoNode); + const containerList = containers(spec, envVars, cardanoNode, cardanoNodePortInstance); try { await apps.readNamespacedDeployment(name, ns); await checkConfigMapExistsOrCreate(core, ns, name, spec, owner); @@ -226,9 +229,11 @@ function containers( spec: Backend.Spec, envVars: V1EnvVar[], cardanoNodeDep: { dependency: DependencyResource; service: ServicePlugin } | null, + cardanoNodePort: ServiceInstanceWithStatusAndKind | null, ): V1Container[] { const args = spec.args ? spec.args.split(' ') : []; const command = spec.command ? spec.command.split(' ') : []; + const volumeMounts: V1VolumeMount[] = [ { name: 'config', @@ -236,7 +241,7 @@ function containers( }, ]; - if (!!cardanoNodeDep) { + if (!!cardanoNodePort || !!cardanoNodeDep) { volumeMounts.push({ name: 'ipc', mountPath: '/ipc', @@ -256,7 +261,9 @@ function containers( }, ]; - if (!!cardanoNodeDep) { + if (!!cardanoNodePort) { + containers.push(buildSocatContainerForPort(cardanoNodePort)); + } else if (!!cardanoNodeDep) { containers.push(buildSocatContainer(cardanoNodeDep.dependency, cardanoNodeDep.service)); } diff --git a/operator/src/frontend/handlers.ts b/operator/src/frontend/handlers.ts index bc7288b..8ae8ea6 100644 --- a/operator/src/frontend/handlers.ts +++ b/operator/src/frontend/handlers.ts @@ -2,11 +2,12 @@ import { PatchUtils, V1Container, V1EnvVar, V1Volume, V1VolumeMount, V1Deploymen import { getClients, readProjectUnsecure, Network, namespaceToSlug, DependencyResource, ServicePlugin } from '@demeter-sdk/framework'; import { API_VERSION, API_GROUP, PLURAL } from './constants'; import { CustomResource, CustomResourceResponse, Frontend, WorkloadStatus } from '@demeter-run/workloads-types'; -import { buildEnvVars, cardanoNodeDep, getDependenciesForNetwork } from '../shared/dependencies'; +import { buildEnvVars, cardanoNodeDep, cardanoNodePort, getDependenciesForNetwork } from '../shared/dependencies'; import { getComputeDCUPerMin, getDeploymentStatus, getNetworkFromAnnotations, getResourcesFromComputeClass, workloadVolumes } from '../shared'; import { checkConfigMapExistsOrCreate, configmap } from '../shared/configmap'; -import { buildSocatContainer } from '../shared/cardano-node-helper'; -import { buildPortEnvVars } from '../shared/ports'; +import { buildSocatContainer, buildSocatContainerForPort } from '../shared/cardano-node-helper'; +import { buildPortEnvVars, getPortsForNetwork } from '../shared/ports'; +import { ServiceInstanceWithStatusAndKind } from '../services'; const tolerations = [ { @@ -45,12 +46,14 @@ export async function handleResource( const network = getNetworkFromAnnotations(spec.annotations) as Network; const deps = await getDependenciesForNetwork(project, network); - const portEnvVars = await buildPortEnvVars(project, network); + const ports = await getPortsForNetwork(project, network); + const portEnvVars = await buildPortEnvVars(ports); const depsEnvVars = await buildEnvVars(deps, network); const envVars = [...depsEnvVars, ...portEnvVars]; const cardanoNode = cardanoNodeDep(deps); + const cardanoNodePortInstance = cardanoNodePort(ports); const volumesList = workloadVolumes(name, !!cardanoNode); - const containerList = containers(spec, envVars, cardanoNode); + const containerList = containers(spec, envVars, cardanoNode, cardanoNodePortInstance); try { await apps.readNamespacedDeployment(name, ns); await checkConfigMapExistsOrCreate(core, ns, name, spec, owner); @@ -211,9 +214,11 @@ function containers( spec: Frontend.Spec, envVars: V1EnvVar[], cardanoNodeDep: { dependency: DependencyResource; service: ServicePlugin } | null, + cardanoNodePort: ServiceInstanceWithStatusAndKind | null, ): V1Container[] { const args = spec.args ? spec.args.split(' ') : []; const command = spec.command ? spec.command.split(' ') : []; + const volumeMounts: V1VolumeMount[] = [ { name: 'config', @@ -221,7 +226,7 @@ function containers( }, ]; - if (!!cardanoNodeDep) { + if (!!cardanoNodePort || !!cardanoNodeDep) { volumeMounts.push({ name: 'ipc', mountPath: '/ipc', @@ -241,7 +246,9 @@ function containers( }, ]; - if (!!cardanoNodeDep) { + if (!!cardanoNodePort) { + containers.push(buildSocatContainerForPort(cardanoNodePort)); + } else if (!!cardanoNodeDep) { containers.push(buildSocatContainer(cardanoNodeDep.dependency, cardanoNodeDep.service)); } diff --git a/operator/src/services.ts b/operator/src/services.ts index db73a3e..d1819ed 100644 --- a/operator/src/services.ts +++ b/operator/src/services.ts @@ -18,6 +18,7 @@ const nodesServiceV2 = nodesV2.SERVICE_PLUGIN; export type ServiceInstanceWithStatus = ServiceInstance & { status: any; spec: any }; +export type ServiceInstanceWithStatusAndKind = ServiceInstanceWithStatus & { kind: string }; /** * Returns all the registered services metadata @@ -30,7 +31,10 @@ export async function getAllServices(): Promise { // checks the service feature flag is enabled for (const id of serviceIds) { - res.push(getServiceMetadata(id)); + const metadata = getServiceMetadata(id); + if (metadata) { + res.push(metadata); + } } return res; diff --git a/operator/src/shared/cardano-node-helper.ts b/operator/src/shared/cardano-node-helper.ts index c105c82..2906b99 100644 --- a/operator/src/shared/cardano-node-helper.ts +++ b/operator/src/shared/cardano-node-helper.ts @@ -2,6 +2,7 @@ import { DependencyResource, EnvVar, Network, ServicePlugin, ServicePort } from import { V1Container } from '@kubernetes/client-node'; import { ServiceInstanceWithStatus } from '../services'; +const CARDANO_NODE_PORT_PORT = 9443; const MAGIC_BY_NETWORK: Record = { preview: '2', preprod: '1', @@ -57,7 +58,7 @@ export function getCardanoNodeEnvVars(dep: DependencyResource, service: ServiceP export function getCardanoNodePortEnvVars(instance: ServiceInstanceWithStatus): EnvVar[] { const network = instance.spec.network; const host = instance.status?.authenticatedEndpointUrl || 'provisioning...'; - const port = 9443; + const port = CARDANO_NODE_PORT_PORT; return [ { name: 'CARDANO_NODE_HOST', value: host }, { name: 'CARDANO_NODE_PORT', value: port }, @@ -85,3 +86,24 @@ export function buildSocatContainer(dep: DependencyResource, service: ServicePlu ], }; } + +export function buildSocatContainerForPort(instance: ServiceInstanceWithStatus): V1Container { + return { + name: 'socat', + image: 'alpine/socat', + securityContext: { + runAsUser: 1000, + runAsGroup: 1000, + }, + args: [ + 'UNIX-LISTEN:/ipc/node.socket,reuseaddr,fork,unlink-early', + `OPENSSL:${instance.status?.authenticatedEndpointUrl}:${CARDANO_NODE_PORT_PORT}` + ], + volumeMounts: [ + { + name: 'ipc', + mountPath: '/ipc', + }, + ], + }; +} diff --git a/operator/src/shared/dependencies.ts b/operator/src/shared/dependencies.ts index 050c6df..cdcdf83 100644 --- a/operator/src/shared/dependencies.ts +++ b/operator/src/shared/dependencies.ts @@ -1,6 +1,6 @@ import { DependencyResource, listDependencies, loadDependencyConnections, Network, ProjectSpec, ServicePlugin } from '@demeter-sdk/framework'; import { V1EnvVar } from '@kubernetes/client-node'; -import { getService } from '../services'; +import { getService, ServiceInstanceWithStatusAndKind } from '../services'; import { getNetworkFromAnnotations } from '.'; import { getCardanoNodeEnvVars } from './cardano-node-helper'; @@ -21,6 +21,19 @@ export function isCardanoNodeEnabled(deps: DependencyResource[]): boolean { return false; } +export function cardanoNodePort(instances: ServiceInstanceWithStatusAndKind[]): ServiceInstanceWithStatusAndKind | null{ + for (const instance of instances) { + if (instance.kind === 'CardanoNodePort') { + return instance; + } + } + return null; +} + +export function isCardanoNodePortEnabled(instances: ServiceInstanceWithStatusAndKind[]): boolean { + return !!cardanoNodePort(instances); +} + export function cardanoNodeDep(deps: DependencyResource[]): { dependency: DependencyResource; service: ServicePlugin } | null { for (const dep of deps) { const service = getService(dep.spec.serviceId); diff --git a/operator/src/shared/ports.ts b/operator/src/shared/ports.ts index 13f2a60..d19d582 100644 --- a/operator/src/shared/ports.ts +++ b/operator/src/shared/ports.ts @@ -1,6 +1,6 @@ import { EnvVar, ProjectSpec } from '@demeter-sdk/framework'; import type { Network, ServiceMetadata } from '@demeter-sdk/framework'; -import { getService, ServiceInstanceWithStatus, getAllServices } from '../services'; +import { getService, ServiceInstanceWithStatus, ServiceInstanceWithStatusAndKind, getAllServices } from '../services'; import { getCardanoNodePortEnvVars } from './cardano-node-helper'; @@ -8,8 +8,29 @@ function removeSchema(url: string): string { return url.replace("https://", '').replace("http://", '') } -export function parseInstanceToEnvVars(instance: ServiceInstanceWithStatus, kind: string): EnvVar[] { - switch (kind) { +export async function getPortsForNetwork(project: ProjectSpec, network: Network): Promise { + const output: ServiceInstanceWithStatusAndKind[] = []; + const services = (await getAllServices()).filter(service => service.key.includes('port')); + + const projectInstances: { metadata: ServiceMetadata; instances: Promise }[] = services.map(svc => { + const service = getService(svc.key)!; + return { metadata: service.metadata, instances: service.listProjectInstances(project) as Promise }; + }); + + for (const projectInstance of projectInstances) { + const inst = await projectInstance.instances; + inst.forEach(instance => { + if (instance.spec.network === network) { + output.push({ ...instance, kind: projectInstance.metadata.kind }) + } + }) + output.push() + } + return output; +} + +export function parseInstanceToEnvVars(instance: ServiceInstanceWithStatusAndKind): EnvVar[] { + switch (instance.kind) { case 'CardanoNodePort': return getCardanoNodePortEnvVars(instance) case 'MarlowePort': @@ -27,23 +48,11 @@ export function parseInstanceToEnvVars(instance: ServiceInstanceWithStatus, kind } } -export async function buildPortEnvVars(project: ProjectSpec, network: Network): Promise { +export async function buildPortEnvVars(instances: ServiceInstanceWithStatusAndKind[]): Promise { const output: EnvVar[] = []; - const services = (await getAllServices()).filter(service => service.key.includes('port')); - - const projectInstances: { metadata: ServiceMetadata; instances: Promise }[] = services.map(svc => { - const service = getService(svc.key)!; - return { metadata: service.metadata, instances: service.listProjectInstances(project) as Promise }; + instances.forEach(item => { + const envVars = parseInstanceToEnvVars(item); + output.push(...envVars); }); - - for (const projectInstance of projectInstances) { - const inst = await projectInstance.instances; - inst.forEach(item => { - if (item.spec.network === network) { - const envVars = parseInstanceToEnvVars(item, projectInstance.metadata.kind); - output.push(...envVars); - } - }); - } return output } diff --git a/operator/src/workspaces/handlers.ts b/operator/src/workspaces/handlers.ts index bc6c4f6..a1cf8cd 100644 --- a/operator/src/workspaces/handlers.ts +++ b/operator/src/workspaces/handlers.ts @@ -12,7 +12,7 @@ import { import { getClients, readProjectUnsecure, Network, namespaceToSlug, DependencySpec, ServicePlugin, DependencyResource } from '@demeter-sdk/framework'; import { API_VERSION, API_GROUP, PLURAL, SINGULAR, KIND, DEFAULT_VSCODE_IMAGE } from './constants'; import { CustomResource, Workspace, StorageClass, CustomResourceResponse } from '@demeter-run/workloads-types'; -import { buildEnvVars, cardanoNodeDep, getDependenciesForNetwork, isCardanoNodeEnabled } from '../shared/dependencies'; +import { buildEnvVars, cardanoNodeDep, cardanoNodePort, getDependenciesForNetwork, isCardanoNodeEnabled } from '../shared/dependencies'; import { getComputeDCUPerMin, getNetworkFromAnnotations, @@ -24,8 +24,9 @@ import { loadPods, } from '../shared'; import { buildDefaultEnvVars, buildDnsZone, INITIAL_ENV_VAR_NAMES } from './helpers'; -import { buildSocatContainer } from '../shared/cardano-node-helper'; -import { buildPortEnvVars } from '../shared/ports'; +import { buildSocatContainer, buildSocatContainerForPort } from '../shared/cardano-node-helper'; +import { buildPortEnvVars, getPortsForNetwork } from '../shared/ports'; +import { ServiceInstanceWithStatusAndKind } from '../services'; const tolerations = [ { @@ -64,13 +65,15 @@ export async function handleResource( const network = getNetworkFromAnnotations(spec.annotations) as Network; const deps = await getDependenciesForNetwork(project, network); + const ports = await getPortsForNetwork(project, network); + const portEnvVars = await buildPortEnvVars(ports); const depsEnvVars = await buildEnvVars(deps, network); - const portEnvVars = await buildPortEnvVars(project, network); const defaultEnvVars = buildDefaultEnvVars(spec); const cardanoNode = cardanoNodeDep(deps); + const cardanoNodePortInstance = cardanoNodePort(ports); const envVars = [...depsEnvVars, ...defaultEnvVars, ...portEnvVars]; const volumesList = volumes(!!cardanoNode); - const containerList = containers(spec, envVars, cardanoNode); + const containerList = containers(spec, envVars, cardanoNode, cardanoNodePortInstance); try { await apps.readNamespacedStatefulSet(name, ns); await updateResource(ns, name, spec, containerList, volumesList, owner); @@ -427,6 +430,7 @@ function containers( spec: Workspace.Spec, envVars: V1EnvVar[], cardanoNodeDep: { dependency: DependencyResource; service: ServicePlugin } | null, + cardanoNodePort: ServiceInstanceWithStatusAndKind | null, patch?: boolean, ): V1Container[] { const volumeMounts: V1VolumeMount[] = [ @@ -436,7 +440,7 @@ function containers( }, ]; - if (!!cardanoNodeDep) { + if (!!cardanoNodePort || !!cardanoNodeDep) { volumeMounts.push({ name: 'ipc', mountPath: '/ipc', @@ -463,7 +467,9 @@ function containers( }, ]; - if (!!cardanoNodeDep) { + if (!!cardanoNodePort) { + containers.push(buildSocatContainerForPort(cardanoNodePort)); + } else if (!!cardanoNodeDep) { containers.push(buildSocatContainer(cardanoNodeDep.dependency, cardanoNodeDep.service)); } diff --git a/package.json b/package.json index a401056..06839f8 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "private": true, "workspaces": [ "operator", - "types", + "types" ], "devDependencies": { "typescript": "^4.7.4"