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

[WIP] tasks #2007

Draft
wants to merge 21 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
690f09b
define tekton tasks in Go
matejvasek Oct 5, 2023
2afb4fb
create s2i pipeline more programatically
matejvasek Oct 6, 2023
b325c45
create s2i pipeline run more programatically
matejvasek Oct 6, 2023
6b9b92d
disable createAndApplyPipelineRunTemplate for s2i
matejvasek Oct 6, 2023
ee3ed10
unify app-image param name between s2i and pack
matejvasek Oct 6, 2023
86337f2
unify sub-path param name between s2i and pack
matejvasek Oct 6, 2023
97950f7
test: use basic Go program (non-Function) in test
matejvasek Oct 25, 2023
fc8f965
feat: create pack pipeline and pipelinerun more programatically
matejvasek Oct 25, 2023
68ab6ee
chore: remove unused code
matejvasek Oct 25, 2023
b075874
disable createAndApplyPipelineRunTemplate for pack
matejvasek Oct 25, 2023
3b9e623
chore: rename function approprietly
matejvasek Oct 25, 2023
c20839e
chore: rename function approprietly
matejvasek Oct 25, 2023
765e3f0
fixup: re-enable possibility to load resources from FS
matejvasek Oct 25, 2023
5241faf
chore: remove unused symbols
matejvasek Oct 25, 2023
e1e8844
fixup: update codegen
matejvasek Oct 25, 2023
5970490
fixup: re-enable tests
matejvasek Oct 25, 2023
5b1d2ee
refactor: move functions
matejvasek Oct 25, 2023
01c5c3e
refactor: rename -- make functions non-exported
matejvasek Oct 25, 2023
9040279
fix: apply labels from PipelineDecorator
matejvasek Oct 31, 2023
2ba9004
fix: keep older version of task
matejvasek Nov 1, 2023
3119564
test: tkn tasks in yaml and Go code as the same
matejvasek Nov 1, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ require (
golang.org/x/sync v0.4.0
golang.org/x/term v0.13.0
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
gotest.tools/v3 v3.4.0
k8s.io/api v0.27.6
k8s.io/apimachinery v0.27.6
Expand Down Expand Up @@ -242,6 +241,7 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.27.6 // indirect
k8s.io/cli-runtime v0.25.9 // indirect
k8s.io/klog/v2 v2.100.1 // indirect
Expand Down
136 changes: 136 additions & 0 deletions pkg/pipelines/resources/tekton/task/func-s2i/0.2/func-s2i.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
apiVersion: tekton.dev/v1beta1
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: APP_IMAGE
description: Reference of the image S2I will produce.
- name: REGISTRY
description: The registry associated with the function image.
- name: SOURCE_SUBPATH
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: quay.io/boson/s2i:latest
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 $(params.SOURCE_SUBPATH) $(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.SOURCE_SUBPATH)" != "" ]; then
func_file="$(workspaces.source.path)/$(params.SOURCE_SUBPATH)/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.APP_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.APP_IMAGE) docker://$(params.APP_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
74 changes: 67 additions & 7 deletions pkg/pipelines/tekton/pipelines_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"knative.dev/func/pkg/k8s"

"knative.dev/func/pkg/builders/buildpacks"
"knative.dev/func/pkg/docker"
fn "knative.dev/func/pkg/functions"
"knative.dev/func/pkg/pipelines/tekton"
Expand Down Expand Up @@ -58,6 +57,7 @@ func TestOnClusterBuild(t *testing.T) {
ns := setupNS(t)

pp := tekton.NewPipelinesProvider(
tekton.WithPipelineDecorator(testDecorator{}),
tekton.WithCredentialsProvider(credentialsProvider),
tekton.WithNamespace(ns))

Expand Down Expand Up @@ -85,10 +85,46 @@ func TestOnClusterBuild(t *testing.T) {
return
}
t.Log("call to knative service successful")

// Check if labels are correct.
cli, err := tekton.NewTektonClients()
if err != nil {
t.Fatal(err)
}
pl, err := cli.Tekton.TektonV1beta1().Pipelines(ns).List(ctx, metav1.ListOptions{})
if len(pl.Items) == 1 {
if val, ok := pl.Items[0].Labels["test-label-key"]; !ok || val != "test-label-value" {
t.Error("test label has not been set for pipeline")
}
} else {
t.Errorf("unexpected pipeline count: %d", len(pl.Items))
}
prl, err := cli.Tekton.TektonV1beta1().PipelineRuns(ns).List(ctx, metav1.ListOptions{})
if err != nil {
t.Fatal(err)
}
if len(prl.Items) == 1 {
if val, ok := prl.Items[0].Labels["test-label-key"]; !ok || val != "test-label-value" {
t.Error("test label has not been set for pipeline run")
}
} else {
t.Errorf("unexpected pipeline run count: %d", len(prl.Items))
}
})
}
}

type testDecorator struct{}

func (t testDecorator) UpdateLabels(function fn.Function, m map[string]string) map[string]string {
result := make(map[string]string, len(m)+1)
for k, v := range m {
result[k] = v
}
result["test-label-key"] = "test-label-value"
return result
}

func setupNS(t *testing.T) string {
name := "pipeline-integration-test-" + strings.ToLower(random.AlphaString(5))
cliSet, err := k8s.NewKubernetesClientset()
Expand Down Expand Up @@ -174,7 +210,7 @@ func createSimpleGoProject(t *testing.T, ns string) fn.Function {
Invoke: "none",
Build: fn.BuildSpec{
BuilderImages: map[string]string{
"pack": buildpacks.DefaultTinyBuilder,
"pack": "index.docker.io/paketobuildpacks/builder-jammy-tiny",
"s2i": "registry.access.redhat.com/ubi8/go-toolset",
},
},
Expand All @@ -190,16 +226,40 @@ func createSimpleGoProject(t *testing.T, ns string) fn.Function {
return f
}

const simpleGOSvc = `package function
const simpleGOSvc = `package main

import (
"context"
"net"
"net/http"
"os"
"os/signal"
"syscall"
)

func Handle(ctx context.Context, resp http.ResponseWriter, req *http.Request) {
resp.Header().Add("Content-Type", "text/plain")
resp.WriteHeader(200)
_, _ = resp.Write([]byte("Hello World!\n"))
func main() {
sigs := make(chan os.Signal, 5)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

s := http.Server{
Handler: http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
resp.Header().Add("Content-Type", "text/plain")
resp.WriteHeader(200)
_, _ = resp.Write([]byte("OK"))
}),
}
go func() {
<-sigs
_ = s.Shutdown(context.Background())
}()
port := "8080"
if p, ok := os.LookupEnv("PORT"); ok {
port = p
}
l, err := net.Listen("tcp4", ":"+port)
if err != nil {
panic(err)
}
_ = s.Serve(l)
}
`