Merge b56a4ccf63 into e3ce0bc457
This commit is contained in:
commit
be032d8a02
|
|
@ -8,6 +8,8 @@ toolbox\-create - Create a new Toolbx container
|
|||
[*--distro DISTRO* | *-d DISTRO*]
|
||||
[*--image NAME* | *-i NAME*]
|
||||
[*--release RELEASE* | *-r RELEASE*]
|
||||
[*--build BUILDCONTEXT* | *-b BUILDCONTEXT*]
|
||||
[*--build-tag TAG* | *-t TAG*]
|
||||
[*CONTAINER*]
|
||||
|
||||
## DESCRIPTION
|
||||
|
|
@ -110,6 +112,22 @@ remote registry.
|
|||
Create a Toolbx container for a different operating system RELEASE than the
|
||||
host. Cannot be used with `--image`.
|
||||
|
||||
**--build** BUILDCONTEXT, **-b** BUILDCONTEXT
|
||||
|
||||
Build a toolbx image from the build context found at BUILDCONTEXT by passing it
|
||||
to `podman build`. Afterwards it sets the tag to `localhost/<name of the image>`
|
||||
by extracting the name from the image and then creates the container like normal.
|
||||
|
||||
You cannot use `--distro`, `--release` or `--image` together with this option.
|
||||
|
||||
**--build-tag** TAG, **-t** TAG
|
||||
|
||||
Overwrites the tagging behaviour of `--build` by tagging the image with TAG via
|
||||
`podman build --tag`. If no repository if given or podman doesn't know it,
|
||||
localhost is used.
|
||||
|
||||
Can only be used when `--build` is also used.
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
### Create the default Toolbx container matching the host OS
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ var (
|
|||
distro string
|
||||
image string
|
||||
release string
|
||||
build string
|
||||
buildtag string
|
||||
}
|
||||
|
||||
createToolboxShMounts = []struct {
|
||||
|
|
@ -104,6 +106,18 @@ func init() {
|
|||
"",
|
||||
"Create a Toolbx container for a different operating system release than the host")
|
||||
|
||||
flags.StringVarP(&createFlags.build,
|
||||
"build",
|
||||
"b",
|
||||
"",
|
||||
"Build a Toolbx container for use of this container")
|
||||
|
||||
flags.StringVarP(&createFlags.buildtag,
|
||||
"build-tag",
|
||||
"t",
|
||||
"",
|
||||
"Tag the image built")
|
||||
|
||||
createCmd.SetHelpFunc(createHelp)
|
||||
|
||||
if err := createCmd.RegisterFlagCompletionFunc("distro", completionDistroNames); err != nil {
|
||||
|
|
@ -147,6 +161,24 @@ func create(cmd *cobra.Command, args []string) error {
|
|||
return errors.New(errMsg)
|
||||
}
|
||||
|
||||
if cmd.Flag("build").Changed && (cmd.Flag("image").Changed || cmd.Flag("release").Changed || cmd.Flag("distro").Changed) {
|
||||
var builder strings.Builder
|
||||
fmt.Fprintf(&builder, "options --build and --release, --image or -- distro cannot be used together\n")
|
||||
fmt.Fprintf(&builder, "Run '%s --help' for usage.", executableBase)
|
||||
|
||||
errMsg := builder.String()
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
|
||||
if cmd.Flag("build-tag").Changed && !cmd.Flag("build").Changed {
|
||||
var builder strings.Builder
|
||||
fmt.Fprintf(&builder, "--build-tag must be used together with --build\n")
|
||||
fmt.Fprintf(&builder, "Run '%s --help' for usage.", executableBase)
|
||||
|
||||
errMsg := builder.String()
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
|
||||
if cmd.Flag("authfile").Changed {
|
||||
if !utils.PathExists(createFlags.authFile) {
|
||||
var builder strings.Builder
|
||||
|
|
@ -174,7 +206,8 @@ func create(cmd *cobra.Command, args []string) error {
|
|||
containerArg,
|
||||
createFlags.distro,
|
||||
createFlags.image,
|
||||
createFlags.release)
|
||||
createFlags.release,
|
||||
podman.BuildOptions{Context: createFlags.build, Tag: createFlags.buildtag})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/containers/toolbox/pkg/podman"
|
||||
"github.com/containers/toolbox/pkg/utils"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
|
@ -108,7 +109,8 @@ func enter(cmd *cobra.Command, args []string) error {
|
|||
containerArg,
|
||||
enterFlags.distro,
|
||||
"",
|
||||
enterFlags.release)
|
||||
enterFlags.release,
|
||||
podman.BuildOptions{Context: "", Tag: ""})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/toolbox/pkg/podman"
|
||||
"github.com/containers/toolbox/pkg/utils"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
|
@ -56,7 +57,7 @@ func rootRunImpl(cmd *cobra.Command, args []string) error {
|
|||
return &exitError{exitCode, err}
|
||||
}
|
||||
|
||||
container, image, release, err := resolveContainerAndImageNames("", "", "", "", "")
|
||||
container, image, release, err := resolveContainerAndImageNames("", "", "", "", "", podman.BuildOptions{Context: "", Tag: ""})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,7 +145,8 @@ func run(cmd *cobra.Command, args []string) error {
|
|||
"--container",
|
||||
runFlags.distro,
|
||||
"",
|
||||
runFlags.release)
|
||||
runFlags.release,
|
||||
podman.BuildOptions{Context: "", Tag: ""})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import (
|
|||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/containers/toolbox/pkg/podman"
|
||||
"github.com/containers/toolbox/pkg/utils"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
|
|
@ -418,13 +419,26 @@ func poll(pollFn pollFunc, eventFD int32, fds ...int32) error {
|
|||
}
|
||||
}
|
||||
|
||||
func resolveContainerAndImageNames(container, containerArg, distroCLI, imageCLI, releaseCLI string) (
|
||||
func resolveContainerAndImageNames(container, containerArg, distroCLI, imageCLI, releaseCLI string, buildCLI podman.BuildOptions) (
|
||||
string, string, string, error,
|
||||
) {
|
||||
container, image, release, err := utils.ResolveContainerAndImageNames(container,
|
||||
distroCLI,
|
||||
imageCLI,
|
||||
releaseCLI)
|
||||
var image, release string
|
||||
var err error
|
||||
if buildCLI.Context == "" {
|
||||
container, image, release, err = utils.ResolveContainerAndImageNames(container,
|
||||
distroCLI,
|
||||
imageCLI,
|
||||
releaseCLI)
|
||||
} else {
|
||||
image, err = podman.BuildImage(buildCLI)
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
container, image, release, err = utils.ResolveContainerAndImageNames(container,
|
||||
distroCLI,
|
||||
image,
|
||||
releaseCLI)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
var errContainer *utils.ContainerError
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/HarryMichal/go-version"
|
||||
|
|
@ -39,6 +41,11 @@ type Image struct {
|
|||
Names []string
|
||||
}
|
||||
|
||||
type BuildOptions struct {
|
||||
Context string
|
||||
Tag string
|
||||
}
|
||||
|
||||
type ImageSlice []Image
|
||||
|
||||
var (
|
||||
|
|
@ -53,6 +60,12 @@ var (
|
|||
LogLevel = logrus.ErrorLevel
|
||||
)
|
||||
|
||||
var (
|
||||
ErrBuildContextDoesNotExist = errors.New("build context does not exist")
|
||||
|
||||
ErrBuildContextInvalid = errors.New("build context is not a directory with a Containerfile")
|
||||
)
|
||||
|
||||
func (image *Image) FlattenNames(fillNameWithID bool) []Image {
|
||||
var ret []Image
|
||||
|
||||
|
|
@ -129,6 +142,52 @@ func (images ImageSlice) Swap(i, j int) {
|
|||
images[i], images[j] = images[j], images[i]
|
||||
}
|
||||
|
||||
func BuildImage(build BuildOptions) (string, error) {
|
||||
if !utils.PathExists(build.Context) {
|
||||
return "", &utils.BuildError{BuildContext: build.Context, Err: ErrBuildContextDoesNotExist}
|
||||
}
|
||||
if stat, err := os.Stat(build.Context); err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
if !stat.Mode().IsDir() {
|
||||
return "", &utils.BuildError{BuildContext: build.Context, Err: ErrBuildContextInvalid}
|
||||
}
|
||||
}
|
||||
if !utils.PathExists(build.Context+"/Containerfile") && !utils.PathExists(build.Context+"/Dockerfile") {
|
||||
return "", &utils.BuildError{BuildContext: build.Context, Err: ErrBuildContextInvalid}
|
||||
}
|
||||
logLevelString := LogLevel.String()
|
||||
args := []string{"--log-level", logLevelString, "build", build.Context}
|
||||
if build.Tag != "" {
|
||||
args = append(args, "--tag", build.Tag)
|
||||
}
|
||||
|
||||
stdout := new(bytes.Buffer)
|
||||
if err := shell.Run("podman", nil, stdout, nil, args...); err != nil {
|
||||
return "", err
|
||||
}
|
||||
output := strings.TrimRight(stdout.String(), "\n")
|
||||
imageIdBegin := strings.LastIndex(output, "\n") + 1
|
||||
imageId := output[imageIdBegin:]
|
||||
|
||||
var name string
|
||||
if build.Tag == "" {
|
||||
info, err := InspectImage(imageId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
name = info["Labels"].(map[string]interface{})["name"].(string)
|
||||
args = []string{"--log-level", logLevelString, "tag", imageId, name}
|
||||
if err := shell.Run("podman", nil, nil, nil, args...); err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
name = build.Tag
|
||||
}
|
||||
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// CheckVersion compares provided version with the version of Podman.
|
||||
//
|
||||
// Takes in one string parameter that should be in the format that is used for versioning (eg. 1.0.0, 2.5.1-dev).
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ func RunContext(ctx context.Context, name string, stdin io.Reader, stdout, stder
|
|||
return err
|
||||
}
|
||||
if exitCode != 0 {
|
||||
return fmt.Errorf("failed to invoke %s(1)", name)
|
||||
return fmt.Errorf("failed to invoke %s(%d)", name, exitCode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,11 @@ type ParseReleaseError struct {
|
|||
Hint string
|
||||
}
|
||||
|
||||
type BuildError struct {
|
||||
BuildContext string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (err *ContainerError) Error() string {
|
||||
errMsg := fmt.Sprintf("%s: %s", err.Container, err.Err)
|
||||
return errMsg
|
||||
|
|
@ -95,3 +100,8 @@ func (err *ImageError) Unwrap() error {
|
|||
func (err *ParseReleaseError) Error() string {
|
||||
return err.Hint
|
||||
}
|
||||
|
||||
func (err *BuildError) Error() string {
|
||||
errMsg := fmt.Sprintf("%s: %s", err.BuildContext, err.Err)
|
||||
return errMsg
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1009,3 +1009,54 @@ teardown() {
|
|||
assert [ ${#lines[@]} -eq 2 ]
|
||||
assert [ ${#stderr_lines[@]} -eq 0 ]
|
||||
}
|
||||
|
||||
@test "create: Build an image before creating the toolbox" {
|
||||
local build_context="./images/fedora/f38"
|
||||
|
||||
run "$TOOLBX" create --build "$build_context"
|
||||
if [ "$status" -ne 0 ]
|
||||
then
|
||||
echo "$output"
|
||||
fi
|
||||
|
||||
assert_line --index 0 "Created container: fedora-toolbox"
|
||||
assert_line --index 1 "Enter with: toolbox enter fedora-toolbox"
|
||||
assert [ ${#lines[@]} -eq 2 ]
|
||||
|
||||
run $PODMAN images --filter reference=localhost/fedora-toolbox
|
||||
assert_success
|
||||
assert [ ${#lines[@]} -eq 2 ]
|
||||
}
|
||||
|
||||
@test "create: Build an image and tag it before creating the toolbox without repository" {
|
||||
local build_context="./images/fedora/f38"
|
||||
local build_tag="testbuild"
|
||||
|
||||
run "$TOOLBX" create --build "$build_context" --build-tag "$build_tag"
|
||||
assert_success
|
||||
|
||||
assert_line --index 0 "Created container: $build_tag"
|
||||
assert_line --index 1 "Enter with: toolbox enter $build_tag"
|
||||
assert [ ${#lines[@]} -eq 2 ]
|
||||
|
||||
run $PODMAN images --filter reference="localhost/$build_tag"
|
||||
assert_success
|
||||
assert [ ${#lines[@]} -eq 2 ]
|
||||
}
|
||||
|
||||
@test "create: Build an image and tag it before creating the toolbox with repository" {
|
||||
local build_context="./images/fedora/f38"
|
||||
local tag_repository="registry.fedoraproject.org"
|
||||
local build_tag="testbuild"
|
||||
|
||||
run "$TOOLBX" create --build "$build_context" --build-tag "$tag_repository/$build_tag"
|
||||
assert_success
|
||||
|
||||
assert_line --index 0 "Created container: $build_tag"
|
||||
assert_line --index 1 "Enter with: toolbox enter $build_tag"
|
||||
assert [ ${#lines[@]} -eq 2 ]
|
||||
|
||||
run $PODMAN images --filter reference="$tag_repository/$build_tag"
|
||||
assert_success
|
||||
assert [ ${#lines[@]} -eq 2 ]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue