mirror of https://github.com/knative/func.git
449 lines
15 KiB
Go
449 lines
15 KiB
Go
package tekton
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
var DeployerImage = "ghcr.io/knative/func-utils:latest"
|
|
|
|
func getBuildpackTask() string {
|
|
return `apiVersion: tekton.dev/v1
|
|
kind: Task
|
|
metadata:
|
|
name: func-buildpacks
|
|
labels:
|
|
app.kubernetes.io/version: "0.1"
|
|
annotations:
|
|
tekton.dev/categories: Image Build
|
|
tekton.dev/pipelines.minVersion: "0.17.0"
|
|
tekton.dev/tags: image-build
|
|
tekton.dev/displayName: "Knative Functions Buildpacks"
|
|
tekton.dev/platforms: "linux/amd64"
|
|
spec:
|
|
description: >-
|
|
The Knative Functions Buildpacks task builds source into a container image and pushes it to a registry,
|
|
using Cloud Native Buildpacks. This task is based on the Buildpacks Tekton task v 0.4.
|
|
|
|
workspaces:
|
|
- name: source
|
|
description: Directory where application source is located.
|
|
- name: cache
|
|
description: Directory where cache is stored (when no cache image is provided).
|
|
optional: true
|
|
- name: dockerconfig
|
|
description: >-
|
|
An optional workspace that allows providing a .docker/config.json file
|
|
for Buildpacks lifecycle binary to access the container registry.
|
|
The file should be placed at the root of the Workspace with name config.json.
|
|
optional: true
|
|
|
|
params:
|
|
- name: APP_IMAGE
|
|
description: The name of where to store the app image.
|
|
- name: REGISTRY
|
|
description: The registry associated with the function image.
|
|
- name: BUILDER_IMAGE
|
|
description: The image on which builds will run (must include lifecycle and compatible buildpacks).
|
|
- name: SOURCE_SUBPATH
|
|
description: A subpath within the "source" input where the source to build is located.
|
|
default: ""
|
|
- name: ENV_VARS
|
|
type: array
|
|
description: Environment variables to set during _build-time_.
|
|
default: []
|
|
- name: RUN_IMAGE
|
|
description: Reference to a run image to use.
|
|
default: ""
|
|
- name: CACHE_IMAGE
|
|
description: The name of the persistent app cache image (if no cache workspace is provided).
|
|
default: ""
|
|
- name: SKIP_RESTORE
|
|
description: Do not write layer metadata or restore cached layers.
|
|
default: "false"
|
|
- name: USER_ID
|
|
description: The user ID of the builder image user.
|
|
default: "1001"
|
|
- name: GROUP_ID
|
|
description: The group ID of the builder image user.
|
|
default: "0"
|
|
##############################################################
|
|
##### "default" has been changed to "0" for Knative Functions
|
|
- name: PLATFORM_DIR
|
|
description: The name of the platform directory.
|
|
default: empty-dir
|
|
|
|
results:
|
|
- name: IMAGE_DIGEST
|
|
description: The digest of the built "APP_IMAGE".
|
|
|
|
stepTemplate:
|
|
env:
|
|
- name: CNB_PLATFORM_API
|
|
value: "0.10"
|
|
|
|
steps:
|
|
- name: prepare
|
|
image: docker.io/library/bash:5.1.4@sha256:b208215a4655538be652b2769d82e576bc4d0a2bb132144c060efc5be8c3f5d6
|
|
args:
|
|
- "--env-vars"
|
|
- "$(params.ENV_VARS[*])"
|
|
script: |
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
|
|
if [[ "$(workspaces.cache.bound)" == "true" ]]; then
|
|
echo "> Setting permissions on '$(workspaces.cache.path)'..."
|
|
chown -R "$(params.USER_ID):$(params.GROUP_ID)" "$(workspaces.cache.path)"
|
|
fi
|
|
|
|
#######################################################
|
|
##### "/emptyDir" has been added for Knative Functions
|
|
for path in "/tekton/home" "/layers" "/emptyDir" "$(workspaces.source.path)"; do
|
|
echo "> Setting permissions on '$path'..."
|
|
chown -R "$(params.USER_ID):$(params.GROUP_ID)" "$path"
|
|
|
|
if [[ "$path" == "$(workspaces.source.path)" ]]; then
|
|
chmod 775 "$(workspaces.source.path)"
|
|
fi
|
|
done
|
|
|
|
echo "> Parsing additional configuration..."
|
|
parsing_flag=""
|
|
envs=()
|
|
for arg in "$@"; do
|
|
if [[ "$arg" == "--env-vars" ]]; then
|
|
echo "-> Parsing env variables..."
|
|
parsing_flag="env-vars"
|
|
elif [[ "$parsing_flag" == "env-vars" ]]; then
|
|
envs+=("$arg")
|
|
fi
|
|
done
|
|
|
|
echo "> Processing any environment variables..."
|
|
ENV_DIR="/platform/env"
|
|
|
|
echo "--> Creating 'env' directory: $ENV_DIR"
|
|
mkdir -p "$ENV_DIR"
|
|
|
|
for env in "${envs[@]}"; do
|
|
IFS='=' read -r key value <<< "$env"
|
|
if [[ "$key" != "" && "$value" != "" ]]; then
|
|
path="${ENV_DIR}/${key}"
|
|
echo "--> Writing ${path}..."
|
|
echo -n "$value" > "$path"
|
|
fi
|
|
done
|
|
|
|
############################################
|
|
##### Added part for Knative Functions #####
|
|
############################################
|
|
|
|
func_file="$(workspaces.source.path)/func.yaml"
|
|
if [ "$(params.SOURCE_SUBPATH)" != "" ]; then
|
|
func_file="$(workspaces.source.path)/$(params.SOURCE_SUBPATH)/func.yaml"
|
|
fi
|
|
echo "--> Saving 'func.yaml'"
|
|
cp $func_file /emptyDir/func.yaml
|
|
|
|
############################################
|
|
|
|
volumeMounts:
|
|
- name: layers-dir
|
|
mountPath: /layers
|
|
- name: $(params.PLATFORM_DIR)
|
|
mountPath: /platform
|
|
########################################################
|
|
##### "/emptyDir" has been added for Knative Functions
|
|
- name: empty-dir
|
|
mountPath: /emptyDir
|
|
|
|
- name: create
|
|
image: $(params.BUILDER_IMAGE)
|
|
imagePullPolicy: Always
|
|
command: ["/cnb/lifecycle/creator"]
|
|
env:
|
|
- name: DOCKER_CONFIG
|
|
value: $(workspaces.dockerconfig.path)
|
|
args:
|
|
- "-app=$(workspaces.source.path)/$(params.SOURCE_SUBPATH)"
|
|
- "-cache-dir=$(workspaces.cache.path)"
|
|
- "-cache-image=$(params.CACHE_IMAGE)"
|
|
- "-uid=$(params.USER_ID)"
|
|
- "-gid=$(params.GROUP_ID)"
|
|
- "-layers=/layers"
|
|
- "-platform=/platform"
|
|
- "-report=/layers/report.toml"
|
|
- "-skip-restore=$(params.SKIP_RESTORE)"
|
|
- "-previous-image=$(params.APP_IMAGE)"
|
|
- "-run-image=$(params.RUN_IMAGE)"
|
|
- "$(params.APP_IMAGE)"
|
|
volumeMounts:
|
|
- name: layers-dir
|
|
mountPath: /layers
|
|
- name: $(params.PLATFORM_DIR)
|
|
mountPath: /platform
|
|
securityContext:
|
|
runAsUser: 1001
|
|
#################################################################
|
|
##### "runAsGroup" has been changed to "0" for Knative Functions
|
|
runAsGroup: 0
|
|
|
|
- name: results
|
|
image: docker.io/library/bash:5.1.4@sha256:b208215a4655538be652b2769d82e576bc4d0a2bb132144c060efc5be8c3f5d6
|
|
script: |
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
cat /layers/report.toml | grep "digest" | cut -d'"' -f2 | cut -d'"' -f2 | tr -d '\n' | tee $(results.IMAGE_DIGEST.path)
|
|
|
|
############################################
|
|
##### Added part for Knative Functions #####
|
|
############################################
|
|
|
|
digest=$(cat $(results.IMAGE_DIGEST.path))
|
|
|
|
func_file="$(workspaces.source.path)/func.yaml"
|
|
if [ "$(params.SOURCE_SUBPATH)" != "" ]; then
|
|
func_file="$(workspaces.source.path)/$(params.SOURCE_SUBPATH)/func.yaml"
|
|
fi
|
|
|
|
if [[ ! -f "$func_file" ]]; then
|
|
echo "--> Restoring 'func.yaml'"
|
|
mkdir -p "$(workspaces.source.path)/$(params.SOURCE_SUBPATH)"
|
|
cp /emptyDir/func.yaml $func_file
|
|
fi
|
|
|
|
echo ""
|
|
sed -i "s|^image:.*$|image: $(params.APP_IMAGE)|" "$func_file"
|
|
echo "Function image name: $(params.APP_IMAGE)"
|
|
|
|
sed -i "s/^imageDigest:.*$/imageDigest: $digest/" "$func_file"
|
|
echo "Function image digest: $digest"
|
|
|
|
sed -i "s|^registry:.*$|registry: $(params.REGISTRY)|" "$func_file"
|
|
echo "Function image registry: $(params.REGISTRY)"
|
|
|
|
############################################
|
|
volumeMounts:
|
|
- name: layers-dir
|
|
mountPath: /layers
|
|
########################################################
|
|
##### "/emptyDir" has been added for Knative Functions
|
|
- name: empty-dir
|
|
mountPath: /emptyDir
|
|
|
|
volumes:
|
|
- name: empty-dir
|
|
emptyDir: {}
|
|
- name: layers-dir
|
|
emptyDir: {}
|
|
`
|
|
}
|
|
|
|
func getS2ITask() string {
|
|
return fmt.Sprintf(`apiVersion: tekton.dev/v1
|
|
kind: Task
|
|
metadata:
|
|
name: func-s2i
|
|
labels:
|
|
app.kubernetes.io/version: "0.1"
|
|
annotations:
|
|
tekton.dev/pipelines.minVersion: "0.17.0"
|
|
tekton.dev/categories: Image Build
|
|
tekton.dev/tags: image-build
|
|
tekton.dev/platforms: "linux/amd64"
|
|
spec:
|
|
description: >-
|
|
Knative Functions Source-to-Image (S2I) is a toolkit and workflow for building reproducible
|
|
container images from source code
|
|
|
|
S2I produces images by injecting source code into a base S2I container image
|
|
and letting the container prepare that source code for execution. The base
|
|
S2I container images contains the language runtime and build tools needed for
|
|
building and running the source code.
|
|
|
|
params:
|
|
- name: BUILDER_IMAGE
|
|
description: The location of the s2i builder image.
|
|
- name: IMAGE
|
|
description: Reference of the image S2I will produce.
|
|
- name: REGISTRY
|
|
description: The registry associated with the function image.
|
|
default: ""
|
|
- name: PATH_CONTEXT
|
|
description: The location of the path to run s2i from.
|
|
default: .
|
|
- name: TLSVERIFY
|
|
description: Verify the TLS on the registry endpoint (for push/pull to a non-TLS registry)
|
|
default: "true"
|
|
- name: LOGLEVEL
|
|
description: Log level when running the S2I binary
|
|
default: "0"
|
|
- name: ENV_VARS
|
|
type: array
|
|
description: Environment variables to set during _build-time_.
|
|
default: []
|
|
- name: S2I_IMAGE_SCRIPTS_URL
|
|
description: The URL containing the default assemble and run scripts for the builder image.
|
|
default: "image:///usr/libexec/s2i"
|
|
workspaces:
|
|
- name: source
|
|
- name: cache
|
|
description: Directory where cache is stored (e.g. local mvn repo).
|
|
optional: true
|
|
- name: sslcertdir
|
|
optional: true
|
|
- name: dockerconfig
|
|
description: >-
|
|
An optional workspace that allows providing a .docker/config.json file
|
|
for Buildah to access the container registry.
|
|
The file should be placed at the root of the Workspace with name config.json.
|
|
optional: true
|
|
results:
|
|
- name: IMAGE_DIGEST
|
|
description: Digest of the image just built.
|
|
steps:
|
|
- name: generate
|
|
image: %s
|
|
workingDir: $(workspaces.source.path)
|
|
args: ["$(params.ENV_VARS[*])"]
|
|
script: |
|
|
echo "Processing Build Environment Variables"
|
|
echo "" > /env-vars/env-file
|
|
for var in "$@"
|
|
do
|
|
if [[ "$var" != "=" ]]; then
|
|
echo "$var" >> /env-vars/env-file
|
|
fi
|
|
done
|
|
|
|
echo "Generated Build Env Var file"
|
|
echo "------------------------------"
|
|
cat /env-vars/env-file
|
|
echo "------------------------------"
|
|
|
|
/usr/local/bin/s2i --loglevel=$(params.LOGLEVEL) build --keep-symlinks $(params.PATH_CONTEXT) $(params.BUILDER_IMAGE) \
|
|
--image-scripts-url $(params.S2I_IMAGE_SCRIPTS_URL) \
|
|
--as-dockerfile /gen-source/Dockerfile.gen --environment-file /env-vars/env-file
|
|
|
|
echo "Preparing func.yaml for later deployment"
|
|
func_file="$(workspaces.source.path)/func.yaml"
|
|
if [ "$(params.PATH_CONTEXT)" != "" ]; then
|
|
func_file="$(workspaces.source.path)/$(params.PATH_CONTEXT)/func.yaml"
|
|
fi
|
|
sed -i "s|^registry:.*$|registry: $(params.REGISTRY)|" "$func_file"
|
|
echo "Function image registry: $(params.REGISTRY)"
|
|
|
|
s2iignore_file="$(dirname "$func_file")/.s2iignore"
|
|
[ -f "$s2iignore_file" ] || echo "node_modules" >> "$s2iignore_file"
|
|
|
|
volumeMounts:
|
|
- mountPath: /gen-source
|
|
name: gen-source
|
|
- mountPath: /env-vars
|
|
name: env-vars
|
|
- name: build
|
|
image: quay.io/buildah/stable:v1.31.0
|
|
workingDir: /gen-source
|
|
script: |
|
|
TLS_VERIFY_FLAG=""
|
|
if [ "$(params.TLSVERIFY)" = "false" ] || [ "$(params.TLSVERIFY)" = "0" ]; then
|
|
TLS_VERIFY_FLAG="--tls-verify=false"
|
|
fi
|
|
|
|
[[ "$(workspaces.sslcertdir.bound)" == "true" ]] && CERT_DIR_FLAG="--cert-dir $(workspaces.sslcertdir.path)"
|
|
ARTIFACTS_CACHE_PATH="$(workspaces.cache.path)/mvn-artifacts"
|
|
[ -d "${ARTIFACTS_CACHE_PATH}" ] || mkdir "${ARTIFACTS_CACHE_PATH}"
|
|
buildah ${CERT_DIR_FLAG} bud --storage-driver=vfs ${TLS_VERIFY_FLAG} --layers \
|
|
-v "${ARTIFACTS_CACHE_PATH}:/tmp/artifacts/:rw,z,U" \
|
|
-f /gen-source/Dockerfile.gen -t $(params.IMAGE) .
|
|
|
|
[[ "$(workspaces.dockerconfig.bound)" == "true" ]] && export DOCKER_CONFIG="$(workspaces.dockerconfig.path)"
|
|
buildah ${CERT_DIR_FLAG} push --storage-driver=vfs ${TLS_VERIFY_FLAG} --digestfile $(workspaces.source.path)/image-digest \
|
|
$(params.IMAGE) docker://$(params.IMAGE)
|
|
|
|
cat $(workspaces.source.path)/image-digest | tee /tekton/results/IMAGE_DIGEST
|
|
volumeMounts:
|
|
- name: varlibcontainers
|
|
mountPath: /var/lib/containers
|
|
- mountPath: /gen-source
|
|
name: gen-source
|
|
securityContext:
|
|
capabilities:
|
|
add: ["SETFCAP"]
|
|
volumes:
|
|
- emptyDir: {}
|
|
name: varlibcontainers
|
|
- emptyDir: {}
|
|
name: gen-source
|
|
- emptyDir: {}
|
|
name: env-vars
|
|
`, DeployerImage)
|
|
}
|
|
|
|
func getDeployTask() string {
|
|
return fmt.Sprintf(`apiVersion: tekton.dev/v1
|
|
kind: Task
|
|
metadata:
|
|
name: func-deploy
|
|
labels:
|
|
app.kubernetes.io/version: "0.1"
|
|
annotations:
|
|
tekton.dev/pipelines.minVersion: "0.12.1"
|
|
tekton.dev/categories: CLI
|
|
tekton.dev/tags: cli
|
|
tekton.dev/platforms: "linux/amd64"
|
|
spec:
|
|
description: >-
|
|
This Task performs a deploy operation using the Knative "func"" CLI
|
|
params:
|
|
- name: path
|
|
description: Path to the function project
|
|
default: ""
|
|
- name: image
|
|
description: Container image to be deployed
|
|
default: ""
|
|
workspaces:
|
|
- name: source
|
|
description: The workspace containing the function project
|
|
steps:
|
|
- name: func-deploy
|
|
image: "%s"
|
|
script: |
|
|
deploy $(params.path) "$(params.image)"
|
|
`, DeployerImage)
|
|
}
|
|
|
|
func getScaffoldTask() string {
|
|
return fmt.Sprintf(`apiVersion: tekton.dev/v1
|
|
kind: Task
|
|
metadata:
|
|
name: func-scaffold
|
|
labels:
|
|
app.kubernetes.io/version: "0.1"
|
|
annotations:
|
|
tekton.dev/pipelines.minVersion: "0.12.1"
|
|
tekton.dev/categories: CLI
|
|
tekton.dev/tags: cli
|
|
tekton.dev/platforms: "linux/amd64"
|
|
spec:
|
|
params:
|
|
- name: path
|
|
description: Path to the function project
|
|
default: ""
|
|
steps:
|
|
- name: func-scaffold
|
|
image: %s
|
|
script: |
|
|
scaffold $(params.path)
|
|
`, DeployerImage)
|
|
}
|
|
|
|
// GetClusterTasks returns multi-document yaml containing tekton tasks used by func.
|
|
func GetClusterTasks() string {
|
|
tasks := getBuildpackTask() + "\n---\n" + getS2ITask() + "\n---\n" + getDeployTask() + "\n---\n" + getScaffoldTask()
|
|
tasks = strings.Replace(tasks, "kind: Task", "kind: ClusterTask", -1)
|
|
tasks = strings.ReplaceAll(tasks, "apiVersion: tekton.dev/v1", "apiVersion: tekton.dev/v1beta1")
|
|
return tasks
|
|
}
|