Skip to content

Commit

Permalink
[release-1.15] Release 1.15.1 (#2480)
Browse files Browse the repository at this point in the history
* test: adding GO s2i to e2e test suite (#2401)

* Remove superfluous equals sign from envvar (#2446)

* Remove superfluous equals sign from envvar

Signed-off-by: Matej Vašek <[email protected]>

* Update rust templates Cargo.lock

Signed-off-by: Matej Vašek <[email protected]>

---------

Signed-off-by: Matej Vašek <[email protected]>

* allow digested images to be 'run' (#2445)

* init fix

Signed-off-by: gauron99 <[email protected]>

* dont override direct deploy tag, more tests

Signed-off-by: gauron99 <[email protected]>

* fix

Signed-off-by: gauron99 <[email protected]>

* dont validate with tagged image, fix comment

Signed-off-by: gauron99 <[email protected]>

* init run fix for --image

Signed-off-by: gauron99 <[email protected]>

* init

Signed-off-by: gauron99 <[email protected]>

* int test, add valid untdigested images to run

Signed-off-by: gauron99 <[email protected]>

* check images passed to runner for func run command

Signed-off-by: gauron99 <[email protected]>

* fix build/deploy image passing bug add test

Signed-off-by: gauron99 <[email protected]>

* fix

Signed-off-by: gauron99 <[email protected]>

* remove extra printing

Signed-off-by: gauron99 <[email protected]>

* merge functions to digested

Signed-off-by: gauron99 <[email protected]>

* misspell

Signed-off-by: gauron99 <[email protected]>

* simplify

Signed-off-by: David Fridrich <[email protected]>

* quick fix

Signed-off-by: David Fridrich <[email protected]>

* remove prints, comment

Signed-off-by: David Fridrich <[email protected]>

---------

Signed-off-by: gauron99 <[email protected]>
Signed-off-by: David Fridrich <[email protected]>

* On cluster s2i build for Go (alternative version) (#2471)

* Prepare util image to accomodate multiple cmds

As of now func-util image has only one command of our own -- "deploy".
This commits prepares grounds for one additional command named "scaffolding".
The commands will be implemented in one binary and dispatched over
argv[0] using symlinks. Kinda like busybox does.

Signed-off-by: Matej Vašek <[email protected]>

* Add scaffolding for on-cluster build

Added new build step in tekton pipeline that scaffolds main() for Go
porject when using s2i builder.

Signed-off-by: Matej Vašek <[email protected]>

* Better docker build caching

This will cache dependencies between docker builds.

Signed-off-by: Matej Vašek <[email protected]>

* fixup: perms

Signed-off-by: Matej Vašek <[email protected]>

* fixup: remove broken check

Signed-off-by: Matej Vašek <[email protected]>

* fixup: remove test because of 'no space left on device'

Signed-off-by: Matej Vašek <[email protected]>

* Make func-util rootfull

Signed-off-by: Matej Vašek <[email protected]>

---------

Signed-off-by: Matej Vašek <[email protected]>

* Incorporate s2i CLI into func-utils image. (#2473)

Signed-off-by: Matej Vašek <[email protected]>

* chore: update Quarkus platform version to 3.14.1 (#2474)

Co-authored-by: Knative Automation <[email protected]>
Signed-off-by: Matej Vašek <[email protected]>

* chore: update Springboot platform version to 3.3.3 (#2465)

Co-authored-by: Knative Automation <[email protected]>
Signed-off-by: Matej Vašek <[email protected]>

---------

Signed-off-by: Matej Vašek <[email protected]>
Signed-off-by: gauron99 <[email protected]>
Signed-off-by: David Fridrich <[email protected]>
Co-authored-by: Jefferson Ramos <[email protected]>
Co-authored-by: David Fridrich <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Knative Automation <[email protected]>
  • Loading branch information
5 people authored Sep 5, 2024
1 parent a511cd9 commit 858a0e8
Show file tree
Hide file tree
Showing 26 changed files with 7,569 additions and 6,717 deletions.
18 changes: 12 additions & 6 deletions Dockerfile.utils
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,30 @@ ARG BUILDPLATFORM
ARG TARGETPLATFORM
ARG TARGETARCH

WORKDIR /workspace

COPY go.mod go.sum ./
RUN go mod download -x

COPY . .

RUN GOARCH=$TARGETARCH go build -o deploy -trimpath -ldflags '-w -s' ./cmd/func-deployer
RUN GOARCH=$TARGETARCH go build -o func-util -trimpath -ldflags '-w -s' ./cmd/func-util

#########################

FROM --platform=$TARGETPLATFORM index.docker.io/library/alpine:latest

RUN apk add --no-cache socat tar \
&& addgroup func -g 1000 \
&& adduser func -u 1001 -D -G func
RUN apk add --no-cache socat tar

COPY --from=builder /go/deploy /usr/local/bin/
COPY --from=builder /workspace/func-util /usr/local/bin/
RUN ln -s /usr/local/bin/func-util /usr/local/bin/deploy && \
ln -s /usr/local/bin/func-util /usr/local/bin/scaffold && \
ln -s /usr/local/bin/func-util /usr/local/bin/s2i

LABEL \
org.opencontainers.image.description="Knative Func Utils Image" \
org.opencontainers.image.source="https://github.com/knative/func" \
org.opencontainers.image.vendor="https://github.com/knative/func" \
org.opencontainers.image.url="https://github.com/knative/func/pkgs/container/func-utils"

USER func:func
USER 0:0
2 changes: 1 addition & 1 deletion cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ func runBuild(cmd *cobra.Command, _ []string, newClient ClientFactory) (err erro
return
}
if cfg.Push {
if f, err = client.Push(cmd.Context(), f); err != nil {
if f, _, err = client.Push(cmd.Context(), f); err != nil {
return
}
}
Expand Down
129 changes: 51 additions & 78 deletions cmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,16 +298,24 @@ func runDeploy(cmd *cobra.Command, newClient ClientFactory) (err error) {
return
}

// Preprocess image name. Validate the image and check whether its digested
// This might alter f.Deploy.Image.
var digested bool
f, digested, err = processImageName(f, cfg.Image)
if err != nil {
return
var (
digested bool
justBuilt bool
justPushed bool
)

// Validate the image and check whether its digested or not
if cfg.Image != "" {
digested, err = isDigested(cfg.Image)
if err != nil {
return
}
// image is valid and undigested
if !digested {
f.Deploy.Image = cfg.Image
}
}

var justBuilt bool

// If user provided --image with digest, they are requesting that specific
// image to be used which means building phase should be skipped and image
// should be deployed as is
Expand All @@ -319,19 +327,18 @@ func runDeploy(cmd *cobra.Command, newClient ClientFactory) (err error) {
return
}
if cfg.Push {
if f, err = client.Push(cmd.Context(), f); err != nil {
if f, justPushed, err = client.Push(cmd.Context(), f); err != nil {
return
}
}
// TODO: gauron99 - temporary fix for undigested image direct deploy (w/out
// build) I think we will be able to remove this after we clean up the
// building process - move the setting of built image in building phase?
if justBuilt && f.Build.Image != "" {
// TODO: gauron99 - temporary fix for undigested image direct deploy
// (w/out build) This might be more complex to do than leaving like this
// image digests are created via the registry on push.
if (justBuilt || justPushed) && f.Build.Image != "" {
// f.Build.Image is set in Push for now, just set it as a deployed image
f.Deploy.Image = f.Build.Image
}
}

if f, err = client.Deploy(cmd.Context(), f, fn.WithDeploySkipBuildCheck(cfg.Build == "false")); err != nil {
return
}
Expand Down Expand Up @@ -372,7 +379,8 @@ func build(cmd *cobra.Command, flag string, f fn.Function, client *fn.Client, bu
}
} else if _, err = strconv.ParseBool(flag); err != nil {
return f, false, fmt.Errorf("--build ($FUNC_BUILD) %q not recognized. Should be 'auto' or a truthy value such as 'true', 'false', '0', or '1'.", flag)

} else if !build {
return f, false, nil
}
return f, true, nil
}
Expand Down Expand Up @@ -671,10 +679,11 @@ func (c deployConfig) Validate(cmd *cobra.Command) (err error) {
}

// Check Image Digest was included
// (will be set on the function during .Configure)
var digest bool
if digest, err = isDigested(c.Image); err != nil {
return
if c.Image != "" {
if digest, err = isDigested(c.Image); err != nil {
return
}
}

// --build can be "auto"|true|false
Expand Down Expand Up @@ -775,44 +784,40 @@ func printDeployMessages(out io.Writer, f fn.Function) {
}
}

// isUndigested returns true if provided image string 'v' has valid tag and false if
// not. It is lenient in validating - does not always throw an error, just
// returning false in some scenarios.
func isUndigested(v string) (validTag bool, err error) {
if strings.Contains(v, "@") {
// digest has been processed separately
return
}
vv := strings.Split(v, ":")
if len(vv) < 2 {
// assume user knows what hes doing
validTag = true
return
} else if len(vv) > 2 {
err = fmt.Errorf("image '%v' contains an invalid tag (extra ':')", v)
return
}
tag := vv[1]
if tag == "" {
err = fmt.Errorf("image '%v' has an empty tag", v)
return
}

validTag = true
return
}

// isDigested returns true if provided image string 'v' has digest and false if not.
// Includes basic validation that a provided digest is correctly formatted.
// Given that image is not digested, image will still be validated and return
// a combination of bool (img has valid digest) and err (img is in valid format)
// Therefore returned combination of [false,nil] means "valid undigested image".
func isDigested(v string) (validDigest bool, err error) {
var digest string
vv := strings.Split(v, "@")
if len(vv) < 2 {
return // has no digest
// image does NOT have a digest, validate further
if v == "" {
err = fmt.Errorf("provided image is empty, cannot validate")
return
}
vvv := strings.Split(v, ":")
if len(vvv) < 2 {
// assume user knows what hes doing
return
} else if len(vvv) > 2 {
err = fmt.Errorf("image '%v' contains an invalid tag (extra ':')", v)
return
}
tag := vvv[1]
if tag == "" {
err = fmt.Errorf("image '%v' has an empty tag", v)
return
}
return
} else if len(vv) > 2 {
// image is invalid
err = fmt.Errorf("image '%v' contains an invalid digest (extra '@')", v)
return
}
// image has a digest, validate further
digest = vv[1]

if !strings.HasPrefix(digest, "sha256:") {
Expand All @@ -827,35 +832,3 @@ func isDigested(v string) (validDigest bool, err error) {
validDigest = true
return
}

// processImageName processes the image name for deployment. It ensures that
// image string is validated if --image was given and ensures that proper
// fields of Function structure are populated if needed.
// Returns a Function structure(1), bool indicating if image was given with
// digest(2) and error(3)
func processImageName(fin fn.Function, configImage string) (f fn.Function, digested bool, err error) {
f = fin
// check if --image was provided with a digest. 'digested' bool indicates if
// image contains a digest or not (image is "digested").
digested, err = isDigested(configImage)
if err != nil {
return
}
// if image is digested, no need to process further
if digested {
return
}
// digested = false here

// valid image can be with/without a tag and might be/not be built next
valid, err := isUndigested(configImage)
if err != nil {
return
}
if valid {
// this can be overridden when build&push=enabled with freshly built
// (digested) image OR directly deployed when build&push=disabled
f.Deploy.Image = configImage
}
return
}
123 changes: 123 additions & 0 deletions cmd/deploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2017,3 +2017,126 @@ func TestDeploy_WithoutHome(t *testing.T) {
t.Fatal(err)
}
}

// TestDeploy_CorrectImageDeployed ensures that deploying will always pass
// the correct image name to the deployer (populating the f.Deploy.Image value)
// in various scenarios.
func TestDeploy_CorrectImageDeployed(t *testing.T) {
const sha = "sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
// dataset
tests := []struct {
name string
image string
buildArgs []string
deployArgs []string
shouldFail bool
shouldBuild bool
pusherActive bool
}{
{
name: "basic test to create and deploy",
image: "myimage",
deployArgs: []string{"--image", "myimage"},
},
{
name: "test to deploy with prebuild",
image: "myimage",
buildArgs: []string{
"--image=myimage",
},
deployArgs: []string{
"--build=false",
},
shouldBuild: true,
},
{
name: "test to build and deploy",
image: "myimage",
buildArgs: []string{
"--image=myimage",
},
shouldBuild: true,
},
{
name: "test to deploy without build should fail",
image: "myimage",
deployArgs: []string{
"--build=false",
},
shouldFail: true,
},
{
name: "test to build then deploy with push",
image: "myimage" + "@" + sha,
buildArgs: []string{
"--image=myimage",
},
deployArgs: []string{
"--build=false",
"--push=true",
},
shouldBuild: true,
pusherActive: true,
},
}

// run tests
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
root := FromTempDirectory(t)
f := fn.Function{
Runtime: "go",
Root: root,
}
_, err := fn.New().Init(f)
if err != nil {
t.Fatal(err)
}

// prebuild function if desired
if tt.shouldBuild {
cmd := NewBuildCmd(NewTestClient(fn.WithRegistry(TestRegistry)))
cmd.SetArgs(tt.buildArgs)
if err = cmd.Execute(); err != nil {
t.Fatal(err)
}
}

pusher := mock.NewPusher()
if tt.pusherActive {
pusher.PushFn = func(_ context.Context, _ fn.Function) (string, error) {
return sha, nil
}
}

deployer := mock.NewDeployer()
deployer.DeployFn = func(_ context.Context, f fn.Function) (result fn.DeploymentResult, err error) {
// verify the image passed to the deployer
if f.Deploy.Image != tt.image {
return fn.DeploymentResult{}, fmt.Errorf("image '%v' does not match the expected image '%v'\n", f.Deploy.Image, tt.image)
}
return
}

// Deploy the function
cmd := NewDeployCmd(NewTestClient(
fn.WithDeployer(deployer), //is always specified
fn.WithPusher(pusher))) // if specified, will return sha for testing

cmd.SetArgs(tt.deployArgs)

// assert
err = cmd.Execute()
if tt.shouldFail {
if err == nil {
t.Fatal("expected an error but got none")
}
} else {
// should not fail
if err != nil {
t.Fatal(err)
}
}
})
}
}
Loading

0 comments on commit 858a0e8

Please sign in to comment.