Skip to content

Commit 858a0e8

Browse files
matejvasekjrangelramosgauron99github-actions[bot]knative-automation
authored
[release-1.15] Release 1.15.1 (#2480)
* 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 <matejvasek@gmail.com> * Update rust templates Cargo.lock Signed-off-by: Matej Vašek <matejvasek@gmail.com> --------- Signed-off-by: Matej Vašek <matejvasek@gmail.com> * allow digested images to be 'run' (#2445) * init fix Signed-off-by: gauron99 <fridrich.david19@gmail.com> * dont override direct deploy tag, more tests Signed-off-by: gauron99 <fridrich.david19@gmail.com> * fix Signed-off-by: gauron99 <fridrich.david19@gmail.com> * dont validate with tagged image, fix comment Signed-off-by: gauron99 <fridrich.david19@gmail.com> * init run fix for --image Signed-off-by: gauron99 <fridrich.david19@gmail.com> * init Signed-off-by: gauron99 <fridrich.david19@gmail.com> * int test, add valid untdigested images to run Signed-off-by: gauron99 <fridrich.david19@gmail.com> * check images passed to runner for func run command Signed-off-by: gauron99 <fridrich.david19@gmail.com> * fix build/deploy image passing bug add test Signed-off-by: gauron99 <fridrich.david19@gmail.com> * fix Signed-off-by: gauron99 <fridrich.david19@gmail.com> * remove extra printing Signed-off-by: gauron99 <fridrich.david19@gmail.com> * merge functions to digested Signed-off-by: gauron99 <fridrich.david19@gmail.com> * misspell Signed-off-by: gauron99 <fridrich.david19@gmail.com> * simplify Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * quick fix Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * remove prints, comment Signed-off-by: David Fridrich <fridrich.david19@gmail.com> --------- Signed-off-by: gauron99 <fridrich.david19@gmail.com> Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * 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 <matejvasek@gmail.com> * 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 <matejvasek@gmail.com> * Better docker build caching This will cache dependencies between docker builds. Signed-off-by: Matej Vašek <matejvasek@gmail.com> * fixup: perms Signed-off-by: Matej Vašek <matejvasek@gmail.com> * fixup: remove broken check Signed-off-by: Matej Vašek <matejvasek@gmail.com> * fixup: remove test because of 'no space left on device' Signed-off-by: Matej Vašek <matejvasek@gmail.com> * Make func-util rootfull Signed-off-by: Matej Vašek <matejvasek@gmail.com> --------- Signed-off-by: Matej Vašek <matejvasek@gmail.com> * Incorporate s2i CLI into func-utils image. (#2473) Signed-off-by: Matej Vašek <matejvasek@gmail.com> * chore: update Quarkus platform version to 3.14.1 (#2474) Co-authored-by: Knative Automation <automation@knative.team> Signed-off-by: Matej Vašek <matejvasek@gmail.com> * chore: update Springboot platform version to 3.3.3 (#2465) Co-authored-by: Knative Automation <automation@knative.team> Signed-off-by: Matej Vašek <matejvasek@gmail.com> --------- Signed-off-by: Matej Vašek <matejvasek@gmail.com> Signed-off-by: gauron99 <fridrich.david19@gmail.com> Signed-off-by: David Fridrich <fridrich.david19@gmail.com> Co-authored-by: Jefferson Ramos <jeramos@redhat.com> Co-authored-by: David Fridrich <49119790+gauron99@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Knative Automation <automation@knative.team>
1 parent a511cd9 commit 858a0e8

26 files changed

+7569
-6717
lines changed

Dockerfile.utils

+12-6
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,30 @@ ARG BUILDPLATFORM
44
ARG TARGETPLATFORM
55
ARG TARGETARCH
66

7+
WORKDIR /workspace
8+
9+
COPY go.mod go.sum ./
10+
RUN go mod download -x
11+
712
COPY . .
813

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

1116
#########################
1217

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

15-
RUN apk add --no-cache socat tar \
16-
&& addgroup func -g 1000 \
17-
&& adduser func -u 1001 -D -G func
20+
RUN apk add --no-cache socat tar
1821

19-
COPY --from=builder /go/deploy /usr/local/bin/
22+
COPY --from=builder /workspace/func-util /usr/local/bin/
23+
RUN ln -s /usr/local/bin/func-util /usr/local/bin/deploy && \
24+
ln -s /usr/local/bin/func-util /usr/local/bin/scaffold && \
25+
ln -s /usr/local/bin/func-util /usr/local/bin/s2i
2026

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

27-
USER func:func
33+
USER 0:0

cmd/build.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ func runBuild(cmd *cobra.Command, _ []string, newClient ClientFactory) (err erro
192192
return
193193
}
194194
if cfg.Push {
195-
if f, err = client.Push(cmd.Context(), f); err != nil {
195+
if f, _, err = client.Push(cmd.Context(), f); err != nil {
196196
return
197197
}
198198
}

cmd/deploy.go

+51-78
Original file line numberDiff line numberDiff line change
@@ -298,16 +298,24 @@ func runDeploy(cmd *cobra.Command, newClient ClientFactory) (err error) {
298298
return
299299
}
300300

301-
// Preprocess image name. Validate the image and check whether its digested
302-
// This might alter f.Deploy.Image.
303-
var digested bool
304-
f, digested, err = processImageName(f, cfg.Image)
305-
if err != nil {
306-
return
301+
var (
302+
digested bool
303+
justBuilt bool
304+
justPushed bool
305+
)
306+
307+
// Validate the image and check whether its digested or not
308+
if cfg.Image != "" {
309+
digested, err = isDigested(cfg.Image)
310+
if err != nil {
311+
return
312+
}
313+
// image is valid and undigested
314+
if !digested {
315+
f.Deploy.Image = cfg.Image
316+
}
307317
}
308318

309-
var justBuilt bool
310-
311319
// If user provided --image with digest, they are requesting that specific
312320
// image to be used which means building phase should be skipped and image
313321
// should be deployed as is
@@ -319,19 +327,18 @@ func runDeploy(cmd *cobra.Command, newClient ClientFactory) (err error) {
319327
return
320328
}
321329
if cfg.Push {
322-
if f, err = client.Push(cmd.Context(), f); err != nil {
330+
if f, justPushed, err = client.Push(cmd.Context(), f); err != nil {
323331
return
324332
}
325333
}
326-
// TODO: gauron99 - temporary fix for undigested image direct deploy (w/out
327-
// build) I think we will be able to remove this after we clean up the
328-
// building process - move the setting of built image in building phase?
329-
if justBuilt && f.Build.Image != "" {
334+
// TODO: gauron99 - temporary fix for undigested image direct deploy
335+
// (w/out build) This might be more complex to do than leaving like this
336+
// image digests are created via the registry on push.
337+
if (justBuilt || justPushed) && f.Build.Image != "" {
330338
// f.Build.Image is set in Push for now, just set it as a deployed image
331339
f.Deploy.Image = f.Build.Image
332340
}
333341
}
334-
335342
if f, err = client.Deploy(cmd.Context(), f, fn.WithDeploySkipBuildCheck(cfg.Build == "false")); err != nil {
336343
return
337344
}
@@ -372,7 +379,8 @@ func build(cmd *cobra.Command, flag string, f fn.Function, client *fn.Client, bu
372379
}
373380
} else if _, err = strconv.ParseBool(flag); err != nil {
374381
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)
375-
382+
} else if !build {
383+
return f, false, nil
376384
}
377385
return f, true, nil
378386
}
@@ -671,10 +679,11 @@ func (c deployConfig) Validate(cmd *cobra.Command) (err error) {
671679
}
672680

673681
// Check Image Digest was included
674-
// (will be set on the function during .Configure)
675682
var digest bool
676-
if digest, err = isDigested(c.Image); err != nil {
677-
return
683+
if c.Image != "" {
684+
if digest, err = isDigested(c.Image); err != nil {
685+
return
686+
}
678687
}
679688

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

778-
// isUndigested returns true if provided image string 'v' has valid tag and false if
779-
// not. It is lenient in validating - does not always throw an error, just
780-
// returning false in some scenarios.
781-
func isUndigested(v string) (validTag bool, err error) {
782-
if strings.Contains(v, "@") {
783-
// digest has been processed separately
784-
return
785-
}
786-
vv := strings.Split(v, ":")
787-
if len(vv) < 2 {
788-
// assume user knows what hes doing
789-
validTag = true
790-
return
791-
} else if len(vv) > 2 {
792-
err = fmt.Errorf("image '%v' contains an invalid tag (extra ':')", v)
793-
return
794-
}
795-
tag := vv[1]
796-
if tag == "" {
797-
err = fmt.Errorf("image '%v' has an empty tag", v)
798-
return
799-
}
800-
801-
validTag = true
802-
return
803-
}
804-
805787
// isDigested returns true if provided image string 'v' has digest and false if not.
806788
// Includes basic validation that a provided digest is correctly formatted.
789+
// Given that image is not digested, image will still be validated and return
790+
// a combination of bool (img has valid digest) and err (img is in valid format)
791+
// Therefore returned combination of [false,nil] means "valid undigested image".
807792
func isDigested(v string) (validDigest bool, err error) {
808793
var digest string
809794
vv := strings.Split(v, "@")
810795
if len(vv) < 2 {
811-
return // has no digest
796+
// image does NOT have a digest, validate further
797+
if v == "" {
798+
err = fmt.Errorf("provided image is empty, cannot validate")
799+
return
800+
}
801+
vvv := strings.Split(v, ":")
802+
if len(vvv) < 2 {
803+
// assume user knows what hes doing
804+
return
805+
} else if len(vvv) > 2 {
806+
err = fmt.Errorf("image '%v' contains an invalid tag (extra ':')", v)
807+
return
808+
}
809+
tag := vvv[1]
810+
if tag == "" {
811+
err = fmt.Errorf("image '%v' has an empty tag", v)
812+
return
813+
}
814+
return
812815
} else if len(vv) > 2 {
816+
// image is invalid
813817
err = fmt.Errorf("image '%v' contains an invalid digest (extra '@')", v)
814818
return
815819
}
820+
// image has a digest, validate further
816821
digest = vv[1]
817822

818823
if !strings.HasPrefix(digest, "sha256:") {
@@ -827,35 +832,3 @@ func isDigested(v string) (validDigest bool, err error) {
827832
validDigest = true
828833
return
829834
}
830-
831-
// processImageName processes the image name for deployment. It ensures that
832-
// image string is validated if --image was given and ensures that proper
833-
// fields of Function structure are populated if needed.
834-
// Returns a Function structure(1), bool indicating if image was given with
835-
// digest(2) and error(3)
836-
func processImageName(fin fn.Function, configImage string) (f fn.Function, digested bool, err error) {
837-
f = fin
838-
// check if --image was provided with a digest. 'digested' bool indicates if
839-
// image contains a digest or not (image is "digested").
840-
digested, err = isDigested(configImage)
841-
if err != nil {
842-
return
843-
}
844-
// if image is digested, no need to process further
845-
if digested {
846-
return
847-
}
848-
// digested = false here
849-
850-
// valid image can be with/without a tag and might be/not be built next
851-
valid, err := isUndigested(configImage)
852-
if err != nil {
853-
return
854-
}
855-
if valid {
856-
// this can be overridden when build&push=enabled with freshly built
857-
// (digested) image OR directly deployed when build&push=disabled
858-
f.Deploy.Image = configImage
859-
}
860-
return
861-
}

cmd/deploy_test.go

+123
Original file line numberDiff line numberDiff line change
@@ -2017,3 +2017,126 @@ func TestDeploy_WithoutHome(t *testing.T) {
20172017
t.Fatal(err)
20182018
}
20192019
}
2020+
2021+
// TestDeploy_CorrectImageDeployed ensures that deploying will always pass
2022+
// the correct image name to the deployer (populating the f.Deploy.Image value)
2023+
// in various scenarios.
2024+
func TestDeploy_CorrectImageDeployed(t *testing.T) {
2025+
const sha = "sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
2026+
// dataset
2027+
tests := []struct {
2028+
name string
2029+
image string
2030+
buildArgs []string
2031+
deployArgs []string
2032+
shouldFail bool
2033+
shouldBuild bool
2034+
pusherActive bool
2035+
}{
2036+
{
2037+
name: "basic test to create and deploy",
2038+
image: "myimage",
2039+
deployArgs: []string{"--image", "myimage"},
2040+
},
2041+
{
2042+
name: "test to deploy with prebuild",
2043+
image: "myimage",
2044+
buildArgs: []string{
2045+
"--image=myimage",
2046+
},
2047+
deployArgs: []string{
2048+
"--build=false",
2049+
},
2050+
shouldBuild: true,
2051+
},
2052+
{
2053+
name: "test to build and deploy",
2054+
image: "myimage",
2055+
buildArgs: []string{
2056+
"--image=myimage",
2057+
},
2058+
shouldBuild: true,
2059+
},
2060+
{
2061+
name: "test to deploy without build should fail",
2062+
image: "myimage",
2063+
deployArgs: []string{
2064+
"--build=false",
2065+
},
2066+
shouldFail: true,
2067+
},
2068+
{
2069+
name: "test to build then deploy with push",
2070+
image: "myimage" + "@" + sha,
2071+
buildArgs: []string{
2072+
"--image=myimage",
2073+
},
2074+
deployArgs: []string{
2075+
"--build=false",
2076+
"--push=true",
2077+
},
2078+
shouldBuild: true,
2079+
pusherActive: true,
2080+
},
2081+
}
2082+
2083+
// run tests
2084+
for _, tt := range tests {
2085+
t.Run(tt.name, func(t *testing.T) {
2086+
root := FromTempDirectory(t)
2087+
f := fn.Function{
2088+
Runtime: "go",
2089+
Root: root,
2090+
}
2091+
_, err := fn.New().Init(f)
2092+
if err != nil {
2093+
t.Fatal(err)
2094+
}
2095+
2096+
// prebuild function if desired
2097+
if tt.shouldBuild {
2098+
cmd := NewBuildCmd(NewTestClient(fn.WithRegistry(TestRegistry)))
2099+
cmd.SetArgs(tt.buildArgs)
2100+
if err = cmd.Execute(); err != nil {
2101+
t.Fatal(err)
2102+
}
2103+
}
2104+
2105+
pusher := mock.NewPusher()
2106+
if tt.pusherActive {
2107+
pusher.PushFn = func(_ context.Context, _ fn.Function) (string, error) {
2108+
return sha, nil
2109+
}
2110+
}
2111+
2112+
deployer := mock.NewDeployer()
2113+
deployer.DeployFn = func(_ context.Context, f fn.Function) (result fn.DeploymentResult, err error) {
2114+
// verify the image passed to the deployer
2115+
if f.Deploy.Image != tt.image {
2116+
return fn.DeploymentResult{}, fmt.Errorf("image '%v' does not match the expected image '%v'\n", f.Deploy.Image, tt.image)
2117+
}
2118+
return
2119+
}
2120+
2121+
// Deploy the function
2122+
cmd := NewDeployCmd(NewTestClient(
2123+
fn.WithDeployer(deployer), //is always specified
2124+
fn.WithPusher(pusher))) // if specified, will return sha for testing
2125+
2126+
cmd.SetArgs(tt.deployArgs)
2127+
2128+
// assert
2129+
err = cmd.Execute()
2130+
if tt.shouldFail {
2131+
if err == nil {
2132+
t.Fatal("expected an error but got none")
2133+
}
2134+
} else {
2135+
// should not fail
2136+
if err != nil {
2137+
t.Fatal(err)
2138+
}
2139+
}
2140+
})
2141+
}
2142+
}

0 commit comments

Comments
 (0)