Skip to content

Commit a91bcc5

Browse files
authored
feat: s2i builder with preliminary node support (#923)
* fix: stuck build ticker * feat: s2i builder prototype * default builders * use s2i fork with updated docker * in-code builder defaults * s2i builder verbosity constructor arg * typed errors * typed error tests * remove unneeded env code * s2i build e2e test * e2e tests * update licenses * cleanup * codegen debug * update licenses * Revert "Update actions (#921)" This reverts commit 8312b5c. * update licenses * e2e test updates * use GetDefaultDockerConfig for s2i config * docker.NewClient docs
1 parent e9251f5 commit a91bcc5

File tree

221 files changed

+31170
-17658
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

221 files changed

+31170
-17658
lines changed

buildpacks/builder.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package buildpacks
33
import (
44
"bytes"
55
"context"
6-
"errors"
76
"fmt"
87
"io"
98
"os"
@@ -21,6 +20,12 @@ import (
2120
"github.com/buildpacks/pack/pkg/logging"
2221
)
2322

23+
// DefaultBuilderImages for Pack builders indexed by Runtime Language
24+
var DefaultBuilderImages = map[string]string{
25+
"node": "gcr.io/paketo-buildpacks/builder:base",
26+
"go": "gcr.io/paketo-buildpacks/builder:base",
27+
}
28+
2429
//Builder holds the configuration that will be passed to
2530
//Buildpack builder
2631
type Builder struct {
@@ -46,7 +51,10 @@ func (builder *Builder) Build(ctx context.Context, f fn.Function) (err error) {
4651
packBuilder = pb
4752
}
4853
} else {
49-
return errors.New("no buildpack configured for function")
54+
packBuilder, err = defaultBuilderImage(f)
55+
if err != nil {
56+
return
57+
}
5058
}
5159

5260
// Build options for the pack client.
@@ -139,6 +147,16 @@ func (builder *Builder) Build(ctx context.Context, f fn.Function) (err error) {
139147
return
140148
}
141149

150+
// defaultBuilderImage for the given function based on its runtime, or an
151+
// error if no default is defined for the given runtime.
152+
func defaultBuilderImage(f fn.Function) (string, error) {
153+
v, ok := DefaultBuilderImages[f.Runtime]
154+
if !ok {
155+
return "", fmt.Errorf("Pack builder has no default builder image specified for the '%v' language runtime. Please provide one.", f.Runtime)
156+
}
157+
return v, nil
158+
}
159+
142160
// hack this makes stdout non-closeable
143161
type stdoutWrapper struct {
144162
impl io.Writer

client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,6 @@ func (c *Client) printBuildActivity(ctx context.Context) {
644644
}
645645
i := 0
646646
ticker := time.NewTicker(10 * time.Second)
647-
defer ticker.Stop()
648647
go func() {
649648
for {
650649
select {
@@ -654,6 +653,7 @@ func (c *Client) printBuildActivity(ctx context.Context) {
654653
i = i % len(m)
655654
case <-ctx.Done():
656655
c.progressListener.Stopping()
656+
ticker.Stop()
657657
return
658658
}
659659
}

client_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -900,8 +900,7 @@ func TestClient_Deploy_UnbuiltErrors(t *testing.T) {
900900
}
901901

902902
// TestClient_New_BuildersPersisted Asserts that the client preserves user-
903-
// provided Builders on the Function configuration with the internal default
904-
// if not provided.
903+
// provided Builders
905904
func TestClient_New_BuildersPersisted(t *testing.T) {
906905
root := "testdata/example.com/testConfiguredBuilders" // Root from which to run the test
907906
defer Using(t, root)()
@@ -931,10 +930,11 @@ func TestClient_New_BuildersPersisted(t *testing.T) {
931930
t.Fatalf("Expected %v but got %v", f0.Builders, f1.Builders)
932931
}
933932

934-
// But that the default exists
935-
if f1.Builder == "" {
936-
t.Fatal("Expected default builder to be set")
937-
}
933+
// A Default Builder(image) is not asserted here, because that is
934+
// the responsibility of the Builder(type) being used to build the Function.
935+
// The builder (Buildpack,s2i, etc) will have a default builder image for
936+
// the given Function or will error that the Function is not supported.
937+
// A builder image may also be manually specified of course.
938938
}
939939

940940
// TestClient_New_BuilderDefault ensures that if a custom builder is

cmd/build.go

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import (
99
"github.com/ory/viper"
1010
"github.com/spf13/cobra"
1111

12+
"knative.dev/kn-plugin-func/buildpacks"
13+
"knative.dev/kn-plugin-func/s2i"
14+
1215
fn "knative.dev/kn-plugin-func"
1316
)
1417

@@ -40,17 +43,18 @@ and the image name is stored in the configuration file.
4043
{{.Name}} build --builder cnbs/sample-builder:bionic
4144
`,
4245
SuggestFor: []string{"biuld", "buidl", "built"},
43-
PreRunE: bindEnv("image", "path", "builder", "registry", "confirm", "push"),
46+
PreRunE: bindEnv("image", "path", "builder", "registry", "confirm", "push", "builder-image"),
4447
}
4548

46-
cmd.Flags().StringP("builder", "b", "", "Buildpack builder, either an as a an image name or a mapping name.\nSpecified value is stored in func.yaml for subsequent builds.")
49+
cmd.Flags().StringP("builder", "b", "pack", "builder to use when creating the underlying image. Currently supported builders are 'pack' and 's2i'.")
50+
cmd.Flags().StringP("builder-image", "", "", "builder image, either an as a an image name or a mapping name.\nSpecified value is stored in func.yaml for subsequent builds. ($FUNC_BUILDER_IMAGE)")
4751
cmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options (Env: $FUNC_CONFIRM)")
4852
cmd.Flags().StringP("image", "i", "", "Full image name in the form [registry]/[namespace]/[name]:[tag] (optional). This option takes precedence over --registry (Env: $FUNC_IMAGE)")
4953
cmd.Flags().StringP("registry", "r", GetDefaultRegistry(), "Registry + namespace part of the image to build, ex 'quay.io/myuser'. The full image name is automatically determined based on the local directory name. If not provided the registry will be taken from func.yaml (Env: $FUNC_REGISTRY)")
5054
cmd.Flags().BoolP("push", "u", false, "Attempt to push the function image after being successfully built")
5155
setPathFlag(cmd)
5256

53-
if err := cmd.RegisterFlagCompletionFunc("builder", CompleteBuilderList); err != nil {
57+
if err := cmd.RegisterFlagCompletionFunc("builder", CompleteBuilderImageList); err != nil {
5458
fmt.Println("internal: error while calling RegisterFlagCompletionFunc: ", err)
5559
}
5660

@@ -89,7 +93,7 @@ func runBuild(cmd *cobra.Command, _ []string, newClient ClientFactory) (err erro
8993
return
9094
}
9195

92-
function, err := functionWithOverrides(config.Path, functionOverrides{Builder: config.Builder, Image: config.Image})
96+
function, err := functionWithOverrides(config.Path, functionOverrides{BuilderImage: config.BuilderImage, Image: config.Image})
9397
if err != nil {
9498
return
9599
}
@@ -144,15 +148,22 @@ func runBuild(cmd *cobra.Command, _ []string, newClient ClientFactory) (err erro
144148
config.Registry = ""
145149
}
146150

147-
// TODO(lkingland): The below deferred options gathering is what will
148-
// re-enable the addition of alternative implementations of the Builder,
149-
// unblocking PR https://github.com/knative-sandbox/kn-plugin-func/pull/842
150-
// the implementation of which will be inserted here.
151+
// Choose a builder based on the value of the --builder flag
152+
var builder fn.Builder
153+
if config.Builder == "pack" {
154+
builder = buildpacks.NewBuilder(config.Verbose)
155+
} else if config.Builder == "s2i" {
156+
builder = s2i.NewBuilder(config.Verbose)
157+
} else {
158+
err = errors.New("unrecognized builder")
159+
return
160+
}
151161

152162
// Create a client using the registry defined in config plus any additional
153163
// options provided (such as mocks for testing)
154164
client, done := newClient(ClientConfig{Verbose: config.Verbose},
155-
fn.WithRegistry(config.Registry))
165+
fn.WithRegistry(config.Registry),
166+
fn.WithBuilder(builder))
156167
defer done()
157168

158169
err = client.Build(cmd.Context(), config.Path)
@@ -184,18 +195,27 @@ type buildConfig struct {
184195
// Confirm: confirm values arrived upon from environment plus flags plus defaults,
185196
// with interactive prompting (only applicable when attached to a TTY).
186197
Confirm bool
198+
199+
// Builder is the name of the subsystem that will complete the underlying
200+
// build (Pack, s2i, remote pipeline, etc). Currently ad-hoc rather than
201+
// an enumerated field. See the Client constructory for logic.
187202
Builder string
203+
204+
// BuilderImage is the image (name or mapping) to use for building. Usually
205+
// set automatically.
206+
BuilderImage string
188207
}
189208

190209
func newBuildConfig() buildConfig {
191210
return buildConfig{
192-
Image: viper.GetString("image"),
193-
Path: viper.GetString("path"),
194-
Registry: viper.GetString("registry"),
195-
Verbose: viper.GetBool("verbose"), // defined on root
196-
Confirm: viper.GetBool("confirm"),
197-
Builder: viper.GetString("builder"),
198-
Push: viper.GetBool("push"),
211+
Image: viper.GetString("image"),
212+
Path: viper.GetString("path"),
213+
Registry: viper.GetString("registry"),
214+
Verbose: viper.GetBool("verbose"), // defined on root
215+
Confirm: viper.GetBool("confirm"),
216+
Builder: viper.GetString("builder"),
217+
BuilderImage: viper.GetString("builder-image"),
218+
Push: viper.GetBool("push"),
199219
}
200220
}
201221

cmd/completion_util.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ func CompleteRegistryList(cmd *cobra.Command, args []string, toComplete string)
9595
return
9696
}
9797

98-
func CompleteBuilderList(cmd *cobra.Command, args []string, complete string) (strings []string, directive cobra.ShellCompDirective) {
98+
func CompleteBuilderImageList(cmd *cobra.Command, args []string, complete string) (strings []string, directive cobra.ShellCompDirective) {
9999
directive = cobra.ShellCompDirectiveError
100100

101101
var (

cmd/root.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,9 @@ func bindEnv(flags ...string) bindFunc {
168168
}
169169

170170
type functionOverrides struct {
171-
Image string
172-
Namespace string
173-
Builder string
171+
Image string
172+
Namespace string
173+
BuilderImage string
174174
}
175175

176176
// functionWithOverrides sets the namespace and image strings for the
@@ -187,7 +187,7 @@ func functionWithOverrides(root string, overrides functionOverrides) (f fn.Funct
187187
src string
188188
dest *string
189189
}{
190-
{overrides.Builder, &f.Builder},
190+
{overrides.BuilderImage, &f.Builder},
191191
{overrides.Image, &f.Image},
192192
{overrides.Namespace, &f.Namespace},
193193
}

docker/docker_client.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ import (
1919
"github.com/docker/docker/client"
2020
)
2121

22+
// NewClient creates a new docker client.
23+
// reads the DOCKER_HOST envvar but it may or may not return it as dockerHost.
24+
// - For local connection (unix socket and windows named pipe) it returns the
25+
// DOCKER_HOST directly.
26+
// - For ssh connections it reads the DOCKER_HOST from the ssh remote.
27+
// - For TCP connections it returns "" so it defaults in the remote (note that
28+
// one should not be use client.DefaultDockerHost in this situation). This is
29+
// needed beaus of TCP+tls connections.
2230
func NewClient(defaultHost string) (dockerClient client.CommonAPIClient, dockerHost string, err error) {
2331
var _url *url.URL
2432

go.mod

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ require (
99
github.com/alecthomas/jsonschema v0.0.0-20210526225647-edb03dcab7bc
1010
github.com/buildpacks/pack v0.24.0
1111
github.com/cloudevents/sdk-go/v2 v2.5.0
12-
github.com/containers/image/v5 v5.10.6
12+
github.com/containers/image/v5 v5.19.1
1313
github.com/coreos/go-semver v0.3.0
1414
github.com/docker/cli v20.10.12+incompatible
1515
github.com/docker/docker v20.10.12+incompatible
@@ -23,6 +23,7 @@ require (
2323
github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c
2424
github.com/mitchellh/go-homedir v1.1.0
2525
github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198
26+
github.com/openshift/source-to-image v1.3.1
2627
github.com/ory/viper v1.7.5
2728
github.com/pkg/errors v0.9.1
2829
github.com/spf13/cobra v1.3.0
@@ -45,6 +46,9 @@ require (
4546
)
4647

4748
replace (
49+
// update docker to be compatible with version used by pack and removes invalid pseudo-version
50+
github.com/openshift/source-to-image => github.com/boson-project/source-to-image v1.3.2
51+
4852
// Pin k8s.io dependencies to align with Knative and Tekton needs
4953
k8s.io/api => k8s.io/api v0.22.5
5054
k8s.io/apimachinery => k8s.io/apimachinery v0.22.5

0 commit comments

Comments
 (0)