Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(openshift): container Build action #4726

Merged
merged 7 commits into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
12 changes: 7 additions & 5 deletions core/src/plugins/kubernetes/container/build/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,13 @@ export async function ensureUtilDeployment({

export async function getManifestInspectArgs(remoteId: string, deploymentRegistry: ContainerRegistryConfig) {
const dockerArgs = ["manifest", "inspect", remoteId]
if (isLocalHostname(deploymentRegistry.hostname)) {
const { hostname } = deploymentRegistry
// Allow insecure connections on local registry
if (
hostname === "localhost" ||
hostname.startsWith("127.") ||
hostname === "default-route-openshift-image-registry.apps-crc.testing"
) {
Comment on lines +360 to +365
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fun fact: here insecure means e.g. allowing self-signed certs etc

dockerArgs.push("--insecure")
}

Expand Down Expand Up @@ -393,10 +399,6 @@ export async function ensureBuilderSecret({
return { authSecret, updated }
}

function isLocalHostname(hostname: string) {
return hostname === "localhost" || hostname.startsWith("127.")
}

Comment on lines -402 to -405
Copy link
Contributor Author

@Walther Walther Jun 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function name sounds way more generic than its actual use was, and it was used only in one place. Inlined to getManifestInspectArgs (with a descriptive comment) to avoid accidental wrong use in other places

export function getUtilContainer(authSecretName: string, provider: KubernetesProvider): V1Container {
return {
name: utilContainerName,
Expand Down
57 changes: 57 additions & 0 deletions core/src/plugins/openshift/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { DeepPrimitiveMap } from "@garden-io/platform-api-types"
import { BuildActionExtension } from "../../plugin/action-types"
import { ContainerBuildAction } from "../container/config"
import { ContainerBuildMode, KubernetesProvider } from "../kubernetes/config"
import { k8sGetContainerBuildActionOutputs } from "../kubernetes/container/handlers"
import { k8sPublishContainerBuild } from "../kubernetes/container/publish"
import { BuildHandler, BuildStatusHandler } from "../kubernetes/container/build/common"
import { getLocalBuildStatus, localBuild } from "../kubernetes/container/build/local"

export const openshiftContainerBuildExtension = (): BuildActionExtension<ContainerBuildAction> => ({
name: "container",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a question. Does name here always equal the value of the corresponding action type?

Copy link
Contributor Author

@Walther Walther Jun 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is directly based on

export const k8sContainerBuildExtension = (): BuildActionExtension<ContainerBuildAction> => ({
name: "container",
handlers: {

handlers: {
async getOutputs({ ctx, action }) {
const provider = ctx.provider as KubernetesProvider
return {
outputs: k8sGetContainerBuildActionOutputs({ action, provider }) as unknown as DeepPrimitiveMap,
}
},

build: async (params) => {
const { ctx } = params

const provider = <KubernetesProvider>ctx.provider
const buildMode = provider.config.buildMode || "local-docker"
const handler = buildHandlers[buildMode]

return handler(params)
},

getStatus: async (params) => {
const { ctx } = params
const provider = <KubernetesProvider>ctx.provider

const buildMode = provider.config.buildMode || "local-docker"
const handler = buildStatusHandlers[buildMode]
return handler(params)
},

publish: k8sPublishContainerBuild,
},
})

const unimplemented = () => {
throw new Error("Unimplemented handler called in OpenShift Build")
}

const buildStatusHandlers: { [mode in ContainerBuildMode]: BuildStatusHandler } = {
"local-docker": getLocalBuildStatus,
"cluster-buildkit": unimplemented,
"kaniko": unimplemented,
}

const buildHandlers: { [mode in ContainerBuildMode]: BuildHandler } = {
"local-docker": localBuild,
"cluster-buildkit": unimplemented,
"kaniko": unimplemented,
}
4 changes: 3 additions & 1 deletion core/src/plugins/openshift/openshift.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@

import { ConfigureProviderParams } from "../../plugin/handlers/Provider/configureProvider"
import { createGardenPlugin } from "../../plugin/plugin"
import { openshiftContainerBuildExtension } from "./build"
import { OpenShiftConfig, configSchema } from "./config"
import { openshiftContainerDeployExtension } from "./container"
import { openshiftContainerDeployExtension } from "./deploy"

export async function configureProvider({ config }: ConfigureProviderParams<OpenShiftConfig>) {
return { config }
Expand All @@ -26,6 +27,7 @@ export const gardenPlugin = () => {

extendActionTypes: {
Deploy: [openshiftContainerDeployExtension()],
Build: [openshiftContainerBuildExtension()],
},
})
}
22 changes: 21 additions & 1 deletion core/test/data/openshift/demo-project/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ There are no guarantees for feature support, correctness, stability, or ice crea

This is mostly internal documentation while we work through adding support for OpenShift.

## Preparation

If you are using Docker Desktop and its builtin Kubernetes support, you need to do the following cleanup steps first:

- Go to Docker Desktop settings, Kubernetes tab, and disable it with the checkbox
- Quit Docker Desktop from the menu - using the Restart button is not enough
- Start Docker Desktop
- Verify that Docker Desktop is no longer binding the port for Kubernetes API server: `lsof -i :6443`
- If the port is still active, you may need to quit and start Docker Desktop again
- Move `~/.kube/config` to another location, both as a backup as well as to give OpenShift the room to create its own

## Setup

- Download OpenShift Local from RedHat's website
Expand All @@ -26,13 +37,22 @@ brew install socat
socat TCP6-LISTEN:6443,fork,reuseaddr TCP4:127.0.0.1:6443
```

This needs to be kept running in the background.

## Deploy

Let's make sure your terminal has fresh credentials in the environment:

```bash
oc login -u developer -p developer https://api.crc.testing:6443
oc registry login --insecure=true
```

Ideally, at this point this should work:

```bash
garden deploy
open http://hello.local.demo.garden/ # NOTE: this will return 403 as there is no content in the served directory and directory listing is forbidden
open http://hello.local.demo.garden/
garden logs nginx-hello # NOTE: this will be empty due to https://github.com/sclorg/nginx-container/issues/94
garden delete deploy
```
3 changes: 3 additions & 0 deletions core/test/data/openshift/demo-project/garden.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ providers:
name: demo-project
context: demo-project/api-crc-testing:6443/developer
cluster: api-crc-testing:6443
deploymentRegistry:
hostname: default-route-openshift-image-registry.apps-crc.testing
namespace: demo-project
3 changes: 3 additions & 0 deletions core/test/data/openshift/demo-project/hello/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM registry.access.redhat.com/ubi8/nginx-122
ADD index.html .
CMD nginx -g "daemon off;"
14 changes: 11 additions & 3 deletions core/test/data/openshift/demo-project/hello/garden.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
kind: Build
type: container
name: openshift-nginx-hello
# FIXME: currently this is required, otherwise you get an ENOENT when calling
# containerHelpers.dockerCli({cwd: action.getBuildPath() ... })
# because the .garden/build directory is not created
buildAtSource: true
Comment on lines +4 to +7
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When trying to do local-docker builds but having the deploymentRegistry set, various methods in our codebase threw ENOENT due to spawn attempting to use a cwd of .garden/build/buildname but nothing had created it in advance. Took a quick look into it but didn't find anything obvious, decided to move on with a workaround to prioritize getting something done.


---
kind: Deploy
type: container
name: nginx-hello
name: openshift-nginx-hello
build: openshift-nginx-hello
spec:
image: registry.access.redhat.com/ubi9/nginx-122:1-12
command: ["nginx", "-g", "daemon off;"]
ports:
- name: http
containerPort: 8080
Expand Down
27 changes: 27 additions & 0 deletions core/test/data/openshift/demo-project/hello/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hello, OpenShift!</title>
<style>
body,
html {
height: 100%;
display: grid;
background: #eee;
margin: 0;
padding: 0;
}
h1 {
margin: auto;
font-family: sans-serif;
font-size: 32pt;
color: #222;
}
</style>
</head>
<body>
<h1>Hello, OpenShift!</h1>
</body>
</html>
20 changes: 17 additions & 3 deletions core/test/integ/src/plugins/openshift/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { LogsCommand } from "../../../../../src/commands/logs"
import { ValidateCommand } from "../../../../../src/commands/validate"
import { getDataDir, makeTestGarden, withDefaultGlobalOpts } from "../../../../helpers"
import { defaultDeployOpts } from "../../../../unit/src/commands/deploy"
import { BuildCommand } from "../../../../../src/commands/build"

describe.skip("OpenShift", () => {
const projectRoot = getDataDir("openshift", "demo-project")
Expand All @@ -34,13 +35,26 @@ describe.skip("OpenShift", () => {
})
})

it("should build a container", async () => {
const command = new BuildCommand()
const { result } = await command.action({
garden,
log,
args: {
names: ["openshift-nginx-hello"],
},
opts: withDefaultGlobalOpts({ "watch": false, "force": true, "with-dependants": false }),
})
expect(result!.success)
})

it("should deploy a container", async () => {
const command = new DeployCommand()
const { result } = await command.action({
garden,
log,
args: {
names: ["nginx-hello"],
names: ["openshift-nginx-hello"],
},
opts: defaultDeployOpts,
})
Expand All @@ -53,7 +67,7 @@ describe.skip("OpenShift", () => {
garden,
log,
args: {
names: ["nginx-hello"],
names: ["openshift-nginx-hello"],
},
opts: withDefaultGlobalOpts({
"log-level": "info",
Expand All @@ -79,6 +93,6 @@ describe.skip("OpenShift", () => {
args: {},
opts: withDefaultGlobalOpts({ "dependants-first": false }),
})
expect(result!.deployStatuses["nginx-hello"].state === "ready")
expect(result!.deployStatuses["openshift-nginx-hello"].state === "ready")
})
})