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*]
|
[*--distro DISTRO* | *-d DISTRO*]
|
||||||
[*--image NAME* | *-i NAME*]
|
[*--image NAME* | *-i NAME*]
|
||||||
[*--release RELEASE* | *-r RELEASE*]
|
[*--release RELEASE* | *-r RELEASE*]
|
||||||
|
[*--build BUILDCONTEXT* | *-b BUILDCONTEXT*]
|
||||||
|
[*--build-tag TAG* | *-t TAG*]
|
||||||
[*CONTAINER*]
|
[*CONTAINER*]
|
||||||
|
|
||||||
## DESCRIPTION
|
## DESCRIPTION
|
||||||
|
|
@ -110,6 +112,22 @@ remote registry.
|
||||||
Create a Toolbx container for a different operating system RELEASE than the
|
Create a Toolbx container for a different operating system RELEASE than the
|
||||||
host. Cannot be used with `--image`.
|
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
|
## EXAMPLES
|
||||||
|
|
||||||
### Create the default Toolbx container matching the host OS
|
### Create the default Toolbx container matching the host OS
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,8 @@ var (
|
||||||
distro string
|
distro string
|
||||||
image string
|
image string
|
||||||
release string
|
release string
|
||||||
|
build string
|
||||||
|
buildtag string
|
||||||
}
|
}
|
||||||
|
|
||||||
createToolboxShMounts = []struct {
|
createToolboxShMounts = []struct {
|
||||||
|
|
@ -104,6 +106,18 @@ func init() {
|
||||||
"",
|
"",
|
||||||
"Create a Toolbx container for a different operating system release than the host")
|
"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)
|
createCmd.SetHelpFunc(createHelp)
|
||||||
|
|
||||||
if err := createCmd.RegisterFlagCompletionFunc("distro", completionDistroNames); err != nil {
|
if err := createCmd.RegisterFlagCompletionFunc("distro", completionDistroNames); err != nil {
|
||||||
|
|
@ -147,6 +161,24 @@ func create(cmd *cobra.Command, args []string) error {
|
||||||
return errors.New(errMsg)
|
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 cmd.Flag("authfile").Changed {
|
||||||
if !utils.PathExists(createFlags.authFile) {
|
if !utils.PathExists(createFlags.authFile) {
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
|
|
@ -174,7 +206,8 @@ func create(cmd *cobra.Command, args []string) error {
|
||||||
containerArg,
|
containerArg,
|
||||||
createFlags.distro,
|
createFlags.distro,
|
||||||
createFlags.image,
|
createFlags.image,
|
||||||
createFlags.release)
|
createFlags.release,
|
||||||
|
podman.BuildOptions{Context: createFlags.build, Tag: createFlags.buildtag})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/containers/toolbox/pkg/podman"
|
||||||
"github.com/containers/toolbox/pkg/utils"
|
"github.com/containers/toolbox/pkg/utils"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
@ -108,7 +109,8 @@ func enter(cmd *cobra.Command, args []string) error {
|
||||||
containerArg,
|
containerArg,
|
||||||
enterFlags.distro,
|
enterFlags.distro,
|
||||||
"",
|
"",
|
||||||
enterFlags.release)
|
enterFlags.release,
|
||||||
|
podman.BuildOptions{Context: "", Tag: ""})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containers/toolbox/pkg/podman"
|
||||||
"github.com/containers/toolbox/pkg/utils"
|
"github.com/containers/toolbox/pkg/utils"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
@ -56,7 +57,7 @@ func rootRunImpl(cmd *cobra.Command, args []string) error {
|
||||||
return &exitError{exitCode, err}
|
return &exitError{exitCode, err}
|
||||||
}
|
}
|
||||||
|
|
||||||
container, image, release, err := resolveContainerAndImageNames("", "", "", "", "")
|
container, image, release, err := resolveContainerAndImageNames("", "", "", "", "", podman.BuildOptions{Context: "", Tag: ""})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,8 @@ func run(cmd *cobra.Command, args []string) error {
|
||||||
"--container",
|
"--container",
|
||||||
runFlags.distro,
|
runFlags.distro,
|
||||||
"",
|
"",
|
||||||
runFlags.release)
|
runFlags.release,
|
||||||
|
podman.BuildOptions{Context: "", Tag: ""})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/containers/toolbox/pkg/podman"
|
||||||
"github.com/containers/toolbox/pkg/utils"
|
"github.com/containers/toolbox/pkg/utils"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/sys/unix"
|
"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,
|
string, string, string, error,
|
||||||
) {
|
) {
|
||||||
container, image, release, err := utils.ResolveContainerAndImageNames(container,
|
var image, release string
|
||||||
distroCLI,
|
var err error
|
||||||
imageCLI,
|
if buildCLI.Context == "" {
|
||||||
releaseCLI)
|
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 {
|
if err != nil {
|
||||||
var errContainer *utils.ContainerError
|
var errContainer *utils.ContainerError
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,9 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/HarryMichal/go-version"
|
"github.com/HarryMichal/go-version"
|
||||||
|
|
@ -39,6 +41,11 @@ type Image struct {
|
||||||
Names []string
|
Names []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BuildOptions struct {
|
||||||
|
Context string
|
||||||
|
Tag string
|
||||||
|
}
|
||||||
|
|
||||||
type ImageSlice []Image
|
type ImageSlice []Image
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -53,6 +60,12 @@ var (
|
||||||
LogLevel = logrus.ErrorLevel
|
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 {
|
func (image *Image) FlattenNames(fillNameWithID bool) []Image {
|
||||||
var ret []Image
|
var ret []Image
|
||||||
|
|
||||||
|
|
@ -129,6 +142,52 @@ func (images ImageSlice) Swap(i, j int) {
|
||||||
images[i], images[j] = images[j], images[i]
|
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.
|
// 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).
|
// 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
|
return err
|
||||||
}
|
}
|
||||||
if exitCode != 0 {
|
if exitCode != 0 {
|
||||||
return fmt.Errorf("failed to invoke %s(1)", name)
|
return fmt.Errorf("failed to invoke %s(%d)", name, exitCode)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,11 @@ type ParseReleaseError struct {
|
||||||
Hint string
|
Hint string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BuildError struct {
|
||||||
|
BuildContext string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
func (err *ContainerError) Error() string {
|
func (err *ContainerError) Error() string {
|
||||||
errMsg := fmt.Sprintf("%s: %s", err.Container, err.Err)
|
errMsg := fmt.Sprintf("%s: %s", err.Container, err.Err)
|
||||||
return errMsg
|
return errMsg
|
||||||
|
|
@ -95,3 +100,8 @@ func (err *ImageError) Unwrap() error {
|
||||||
func (err *ParseReleaseError) Error() string {
|
func (err *ParseReleaseError) Error() string {
|
||||||
return err.Hint
|
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 [ ${#lines[@]} -eq 2 ]
|
||||||
assert [ ${#stderr_lines[@]} -eq 0 ]
|
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