Skip to content

Commit f6e6021

Browse files
authored
Remove container flag - variant I (knative#2987)
1 parent c48dbc1 commit f6e6021

File tree

4 files changed

+55
-206
lines changed

4 files changed

+55
-206
lines changed

cmd/run.go

Lines changed: 35 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ NAME
2828
{{rootCmdUse}} run - Run a function locally
2929
3030
SYNOPSIS
31-
{{rootCmdUse}} run [-t|--container] [-r|--registry] [-i|--image] [-e|--env]
32-
[--build] [-b|--builder] [--builder-image] [-c|--confirm]
31+
{{rootCmdUse}} run [-r|--registry] [-i|--image] [-e|--env] [--build]
32+
[-b|--builder] [--builder-image] [-c|--confirm]
3333
[--address] [--json] [-v|--verbose]
3434
3535
DESCRIPTION
@@ -38,38 +38,32 @@ DESCRIPTION
3838
Values provided for flags are not persisted to the function's metadata.
3939
4040
Containerized Runs
41-
The --container flag indicates that the function's container should be
42-
run rather than running the source code directly. This may require that
43-
the function's container first be rebuilt. Building the container on or
44-
off can be altered using the --build flag. The value --build=auto
45-
can be used to indicate the function should be run in a container, with
46-
the container automatically built if necessary.
47-
48-
The --container flag defaults to true if the builder defined for the
49-
function is a containerized builder such as Pack or S2I, and in the case
50-
where the function's runtime requires containerized builds (is not yet
51-
supported by the Host builder.
41+
You can build your function in a container using the Pack or S2i builders.
42+
On the contrary, non-containerized run is achieved via Host builder which
43+
will use your host OS' environment to build the function. This builder is
44+
currently enabled for Go and Python. Building defaults to using the Host
45+
builder when available. You can alter this by using the --builder flag
46+
eg: --builder=s2i.
5247
5348
Process Scaffolding
54-
This is an Experimental Feature currently available only to Go projects.
55-
When running a function with --container=false (host-based runs), the
56-
function is first wrapped code which presents it as a process.
57-
This "scaffolding" is transient, written for each build or run, and should
58-
in most cases be transparent to a function author. However, to customize,
59-
or even completely replace this scafolding code, see the 'scaffold'
60-
subcommand.
49+
This is an Experimental Feature currently available only to Go and Python
50+
projects. When running a function with --builder=host, the function is
51+
first wrapped with code which presents it as a process. This "scaffolding"
52+
is transient, written for each build or run, and should in most cases be
53+
transparent to a function author.
6154
6255
EXAMPLES
6356
6457
o Run the function locally from within its container.
6558
$ {{rootCmdUse}} run
6659
6760
o Run the function locally from within its container, forcing a rebuild
68-
of the container even if no filesysem changes are detected
69-
$ {{rootCmdUse}} run --build
61+
of the container even if no filesystem changes are detected. There are 2
62+
builders available for containerized build - 'pack' and 's2i'.
63+
$ {{rootCmdUse}} run --build=<builder>
7064
71-
o Run the function locally on the host with no containerization (Go only).
72-
$ {{rootCmdUse}} run --container=false
65+
o Run the function locally on the host with no containerization (Go/Python only).
66+
$ {{rootCmdUse}} run --builder=host
7367
7468
o Run the function locally on a specific address.
7569
$ {{rootCmdUse}} run --address='[::]:8081'
@@ -79,7 +73,7 @@ EXAMPLES
7973
`,
8074
SuggestFor: []string{"rnu"},
8175
PreRunE: bindEnv("build", "builder", "builder-image", "base-image",
82-
"confirm", "container", "env", "image", "path", "registry",
76+
"confirm", "env", "image", "path", "registry",
8377
"start-timeout", "verbose", "address", "json"),
8478
RunE: func(cmd *cobra.Command, _ []string) error {
8579
return runRun(cmd, newClient)
@@ -121,8 +115,6 @@ EXAMPLES
121115
"You may provide this flag multiple times for setting multiple environment variables. "+
122116
"To unset, specify the environment variable name followed by a \"-\" (e.g., NAME-).")
123117
cmd.Flags().Duration("start-timeout", f.Run.StartTimeout, fmt.Sprintf("time this function needs in order to start. If not provided, the client default %v will be in effect. ($FUNC_START_TIMEOUT)", fn.DefaultStartTimeout))
124-
cmd.Flags().BoolP("container", "t", runContainerizedByDefault(f),
125-
"Run the function in a container. ($FUNC_CONTAINER)")
126118

127119
// TODO: Without the "Host" builder enabled, this code-path is unreachable,
128120
// so remove hidden flag when either the Host builder path is available,
@@ -157,10 +149,6 @@ EXAMPLES
157149
return cmd
158150
}
159151

160-
func runContainerizedByDefault(f fn.Function) bool {
161-
return f.Build.Builder == "pack" || f.Build.Builder == "s2i" || !oci.IsSupported(f.Runtime)
162-
}
163-
164152
func runRun(cmd *cobra.Command, newClient ClientFactory) (err error) {
165153
var (
166154
cfg runConfig
@@ -174,28 +162,17 @@ func runRun(cmd *cobra.Command, newClient ClientFactory) (err error) {
174162
if !f.Initialized() {
175163
return fn.NewErrNotInitialized(f.Root)
176164
}
177-
if f, err = cfg.Configure(f); err != nil { // Updates f with deploy cfg
178-
return
179-
}
180-
181-
// Smart auto-fix logic for builder/container compatibility
182-
// This fixes the original bug where --builder=pack doesn't default to container=true
183165

184-
// Case 1: Containerized builders (pack/s2i) should force container=true when not explicitly set
185-
if (f.Build.Builder == "pack" || f.Build.Builder == "s2i") && !cfg.Container && !cmd.Flags().Changed("container") {
186-
cfg.Container = true
187-
}
188-
189-
// Case 2: container=false should auto-select host builder when no builder explicitly set
190-
if !cfg.Container && cmd.Flags().Changed("container") && !cmd.Flags().Changed("builder") {
191-
f.Build.Builder = "host"
166+
if err = cfg.Validate(cmd, f); err != nil {
167+
return
192168
}
193169

194-
// Validate after configure and auto-fix
195-
if err = cfg.Validate(cmd, f); err != nil {
170+
if f, err = cfg.Configure(f); err != nil { // Updates f with deploy cfg
196171
return
197172
}
198173

174+
container := f.Build.Builder != "host"
175+
199176
// Ignore the verbose flag if JSON output
200177
if cfg.JSON {
201178
cfg.Verbose = false
@@ -206,7 +183,7 @@ func runRun(cmd *cobra.Command, newClient ClientFactory) (err error) {
206183
if err != nil {
207184
return
208185
}
209-
if cfg.Container {
186+
if container {
210187
clientOptions = append(clientOptions, fn.WithRunner(docker.NewRunner(cfg.Verbose, os.Stdout, os.Stderr)))
211188
}
212189
if cfg.StartTimeout != 0 {
@@ -220,7 +197,7 @@ func runRun(cmd *cobra.Command, newClient ClientFactory) (err error) {
220197
//
221198
// If requesting to run via the container, build the container if it is
222199
// either out-of-date or a build was explicitly requested.
223-
if cfg.Container {
200+
if container {
224201
var digested bool
225202

226203
buildOptions, err := cfg.buildOptions()
@@ -234,31 +211,25 @@ func runRun(cmd *cobra.Command, newClient ClientFactory) (err error) {
234211
if err != nil {
235212
return err
236213
}
237-
if !digested {
238-
// assign valid undigested image
239-
f.Build.Image = cfg.Image
240-
}
241-
}
242-
243-
if digested {
244-
// run cmd takes f.Build.Image - see newContainerConfig in docker/runner.go
245-
// it doesnt get saved, just runtime image
214+
// image was parsed and both digested AND undigested imgs are valid
246215
f.Build.Image = cfg.Image
247-
} else {
216+
}
248217

218+
// actual build step
219+
if !digested {
249220
if f, _, err = build(cmd, cfg.Build, f, client, buildOptions); err != nil {
250221
return err
251222
}
252223
}
253-
} else {
224+
} else { // if !container
254225
// dont run digested image without a container
255226
if cfg.Image != "" {
256227
digested, err := isDigested(cfg.Image)
257228
if err != nil {
258229
return err
259230
}
260231
if digested {
261-
return fmt.Errorf("cannot use digested image with --container=false")
232+
return fmt.Errorf("cannot use digested image with non-containerized builds (--builder=host)")
262233
}
263234
}
264235
}
@@ -330,10 +301,6 @@ type runConfig struct {
330301
// Can be 'auto' or a truthy value.
331302
Build string
332303

333-
// Container indicates the function should be run in a container.
334-
// Requires the container be built.
335-
Container bool
336-
337304
// Env variables. may include removals using a "-"
338305
Env []string
339306

@@ -353,7 +320,6 @@ func newRunConfig(cmd *cobra.Command) (c runConfig) {
353320
buildConfig: newBuildConfig(),
354321
Build: viper.GetString("build"),
355322
Env: viper.GetStringSlice("env"),
356-
Container: viper.GetBool("container"),
357323
StartTimeout: viper.GetDuration("start-timeout"),
358324
Address: viper.GetString("address"),
359325
JSON: viper.GetBool("json"),
@@ -379,7 +345,7 @@ func (c runConfig) Configure(f fn.Function) (fn.Function, error) {
379345

380346
f.Run.Envs, err = applyEnvs(f.Run.Envs, c.Env)
381347

382-
// The other members; build, path, and container; are not part of function
348+
// The other members; build and path; are not part of function
383349
// state, so are not mentioned here in Configure.
384350
return f, err
385351
}
@@ -412,18 +378,13 @@ func (c runConfig) Validate(cmd *cobra.Command, f fn.Function) (err error) {
412378
}
413379
}
414380

415-
if !c.Container && !oci.IsSupported(f.Runtime) {
381+
if f.Build.Builder == "host" && !oci.IsSupported(f.Runtime) {
416382
return fmt.Errorf("the %q runtime currently requires being run in a container", f.Runtime)
417383
}
418384

419-
// Validate that containerized builders (pack/s2i) cannot be used with container=false
420-
if (f.Build.Builder == "pack" || f.Build.Builder == "s2i") && !c.Container {
421-
return fmt.Errorf("builder %q requires container mode but --container=false was set", f.Build.Builder)
422-
}
423-
424385
// When the docker runner respects the StartTimeout, this validation check
425386
// can be removed
426-
if c.StartTimeout != 0 && c.Container {
387+
if c.StartTimeout != 0 && f.Build.Builder != "host" {
427388
return errors.New("the ability to specify the startup timeout for containerized runs is coming soon")
428389
}
429390

cmd/run_test.go

Lines changed: 0 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package cmd
33
import (
44
"context"
55
"fmt"
6-
"path/filepath"
76
"testing"
87
"time"
98

@@ -602,107 +601,3 @@ func TestRun_BaseImage(t *testing.T) {
602601
})
603602
}
604603
}
605-
606-
// TestCtrBuilder tests that pack builder auto-forces container mode
607-
func TestCtrBuilder(t *testing.T) {
608-
var runner = mock.NewRunner()
609-
var builder = mock.NewBuilder()
610-
tmp := t.TempDir()
611-
612-
fnPath := filepath.Join(tmp, "fn")
613-
f, err := fn.New().Init(fn.Function{Root: fnPath, Runtime: "python"})
614-
if err != nil {
615-
t.Fatal(err)
616-
}
617-
err = f.Write()
618-
if err != nil {
619-
t.Fatal(err)
620-
}
621-
t.Chdir(fnPath)
622-
623-
cmd := NewRunCmd(NewTestClient(
624-
fn.WithRunner(runner),
625-
fn.WithBuilder(builder),
626-
fn.WithRegistry(TestRegistry),
627-
))
628-
cmd.SetArgs([]string{"--builder=pack", "--build=1"})
629-
ctx, cancel := context.WithCancel(context.Background())
630-
time.AfterFunc(time.Second, func() {
631-
cancel()
632-
})
633-
err = cmd.ExecuteContext(ctx)
634-
if err != nil {
635-
t.Fatal(err)
636-
}
637-
// verify that builder was called since `--builder=pack` was provided
638-
if !builder.BuildInvoked {
639-
t.Error("builder has not been invoked")
640-
}
641-
}
642-
643-
// TestCtrBuilderConflict tests that pack builder with explicit container=false shows validation error
644-
func TestCtrBuilderConflict(t *testing.T) {
645-
var runner = mock.NewRunner()
646-
var builder = mock.NewBuilder()
647-
tmp := t.TempDir()
648-
649-
fnPath := filepath.Join(tmp, "fn")
650-
f, err := fn.New().Init(fn.Function{Root: fnPath, Runtime: "python"})
651-
if err != nil {
652-
t.Fatal(err)
653-
}
654-
err = f.Write()
655-
if err != nil {
656-
t.Fatal(err)
657-
}
658-
t.Chdir(fnPath)
659-
660-
cmd := NewRunCmd(NewTestClient(
661-
fn.WithRunner(runner),
662-
fn.WithBuilder(builder),
663-
fn.WithRegistry(TestRegistry),
664-
))
665-
cmd.SetArgs([]string{"--builder=pack", "--build=1", "--container=0"})
666-
ctx, cancel := context.WithCancel(context.Background())
667-
time.AfterFunc(time.Second, func() {
668-
cancel()
669-
})
670-
err = cmd.ExecuteContext(ctx)
671-
// since explicit flag `--builder=pack` and `--container=0` are contradiction we want error
672-
if err == nil {
673-
t.Error("error expected but got <nil>")
674-
}
675-
}
676-
677-
// TestSmartBuilderSelection tests that container=false auto-selects host builder
678-
func TestSmartBuilderSelection(t *testing.T) {
679-
var runner = mock.NewRunner()
680-
var builder = mock.NewBuilder()
681-
tmp := t.TempDir()
682-
683-
fnPath := filepath.Join(tmp, "fn")
684-
f, err := fn.New().Init(fn.Function{Root: fnPath, Runtime: "go"})
685-
if err != nil {
686-
t.Fatal(err)
687-
}
688-
err = f.Write()
689-
if err != nil {
690-
t.Fatal(err)
691-
}
692-
t.Chdir(fnPath)
693-
694-
cmd := NewRunCmd(NewTestClient(
695-
fn.WithRunner(runner),
696-
fn.WithBuilder(builder),
697-
fn.WithRegistry(TestRegistry),
698-
))
699-
cmd.SetArgs([]string{"--container=false", "--build=1"})
700-
ctx, cancel := context.WithCancel(context.Background())
701-
time.AfterFunc(time.Second, func() {
702-
cancel()
703-
})
704-
err = cmd.ExecuteContext(ctx)
705-
if err != nil {
706-
t.Fatal(err)
707-
}
708-
}

0 commit comments

Comments
 (0)