toolbox-0.0.99.2-2.el9

- Actually apply the patch to make 'toolbox' create or fall back to a
  container if possible
- Support logging into a registry if necessary
- Resolves: #1977343

Signed-off-by: Jindrich Novy <jnovy@redhat.com>
This commit is contained in:
Jindrich Novy 2021-07-05 13:13:58 +02:00
parent 72d3271661
commit 067c49f5d1
8 changed files with 849 additions and 51 deletions

26
.gitignore vendored
View File

@ -1,25 +1 @@
/toolbox-0.0.6.tar.xz
/toolbox-0.0.7.tar.xz
/toolbox-0.0.8.tar.xz
/toolbox-0.0.9.tar.xz
/toolbox-0.0.10.tar.xz
/toolbox-0.0.11.tar.xz
/toolbox-0.0.12.tar.xz
/toolbox-0.0.13.tar.xz
/toolbox-0.0.14.tar.xz
/toolbox-0.0.15.tar.xz
/toolbox-0.0.16.tar.xz
/toolbox-0.0.17.tar.xz
/toolbox-0.0.18.tar.xz
/toolbox-0.0.91.tar.xz
/toolbox-0.0.92.tar.xz
/toolbox-0.0.93.tar.xz
/toolbox-0.0.94.tar.xz
/toolbox-0.0.95.tar.xz
/toolbox-0.0.96.tar.xz
/toolbox-0.0.97.tar.xz
/toolbox-0.0.98.tar.xz
/toolbox-0.0.98.1.tar.xz
/toolbox-0.0.99.tar.xz
/toolbox-0.0.99.1.tar.xz
/toolbox-0.0.99.1-vendored.tar.xz
/*.tar.xz

View File

@ -1,3 +0,0 @@
# toolbox
The toolbox package

View File

@ -1 +1 @@
SHA512 (toolbox-0.0.99.2-vendored.tar.xz) = 44eab6eb98fc8e52e03fc753e1c26e5d2d8a91e5ba84817bbf76f7dc6601581b5922115c140637951074ab8d741f443b3217a07639ea4d7bdf81d5faf836e3b2
SHA512 (toolbox-0.0.99.2-vendored.tar.xz) = 44eab6eb98fc8e52e03fc753e1c26e5d2d8a91e5ba84817bbf76f7dc6601581b5922115c140637951074ab8d741f443b3217a07639ea4d7bdf81d5faf836e3b2

View File

@ -1,30 +1,30 @@
From e9bfc40bbbf7af1a20819b6840441cbe52a7d1b7 Mon Sep 17 00:00:00 2001
From a245af969792bafcfa86090c856a06cb23061816 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <rishi@fedoraproject.org>
Date: Mon, 29 Jun 2020 17:57:47 +0200
Subject: [PATCH] build: Make the build flags match Fedora's %{gobuild} for
PPC64
Subject: [PATCH] build: Make the build flags match RHEL's %{gobuild} for PPC64
The Go toolchain doesn't play well with passing compiler and linker
flags via environment variables. The linker flags require a second
level of quoting, which leaves the build system without a quote level
to assign the flags to an environment variable like GOFLAGS.
This is one reason why Fedora doesn't have a RPM macro with only the
This is one reason why RHEL doesn't have a RPM macro with only the
flags. The %{gobuild} RPM macro includes the entire 'go build ...'
invocation.
The Go toolchain also doesn't like the LDFLAGS environment variable as
exported by Fedora's %{meson} RPM macro.
exported by RHEL's %{meson} RPM macro, and RHEL's RPM toolchain doesn't
like the compressed DWARF data generated by the Go toolchain.
Note that these flags are only meant for the "ppc64" CPU architecture,
and should be kept updated to match Fedora's Go guidelines. Use
and should be kept updated to match RHEL's Go guidelines. Use
'rpm --eval "%{gobuild}"' to expand the %{gobuild} macro.
---
src/go-build-wrapper | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/go-build-wrapper b/src/go-build-wrapper
index 515e1d8a0670..8baaff53b329 100755
index 0d27120da052..ef1a03af750a 100755
--- a/src/go-build-wrapper
+++ b/src/go-build-wrapper
@@ -27,5 +27,6 @@ if ! cd "$1"; then
@ -33,8 +33,8 @@ index 515e1d8a0670..8baaff53b329 100755
-go build -trimpath -ldflags "-extldflags '-Wl,--wrap,pthread_sigmask $4' -linkmode external -X github.com/containers/toolbox/pkg/version.currentVersion=$3" -o "$2/toolbox"
+unset LDFLAGS
+go build -compiler gc -tags="rpm_crashtraceback ${BUILDTAGS:-}" -ldflags "${LDFLAGS:-} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \n') -extldflags '-Wl,-z,relro -Wl,--as-needed -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,--wrap,pthread_sigmask $4' -linkmode external -X github.com/containers/toolbox/pkg/version.currentVersion=$3" -a -v -x -o "$2/toolbox"
+go build -compiler gc -tags="rpm_crashtraceback ${BUILDTAGS:-}" -ldflags "${LDFLAGS:-} -compressdwarf=false -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \n') -extldflags '-Wl,-z,relro -Wl,--as-needed -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,--wrap,pthread_sigmask $4' -linkmode external -X github.com/containers/toolbox/pkg/version.currentVersion=$3" -a -v -x -o "$2/toolbox"
exit "$?"
--
2.29.2
2.31.1

View File

@ -1,29 +1,30 @@
From d204528ce3b3c70727c12e1911d1c5562b56d474 Mon Sep 17 00:00:00 2001
From 05722d2861c23554b9741c059e853da9ab38282e Mon Sep 17 00:00:00 2001
From: Debarshi Ray <rishi@fedoraproject.org>
Date: Mon, 29 Jun 2020 17:57:47 +0200
Subject: [PATCH] build: Make the build flags match Fedora's %{gobuild}
Subject: [PATCH] build: Make the build flags match RHEL's %{gobuild}
The Go toolchain doesn't play well with passing compiler and linker
flags via environment variables. The linker flags require a second
level of quoting, which leaves the build system without a quote level
to assign the flags to an environment variable like GOFLAGS.
This is one reason why Fedora doesn't have a RPM macro with only the
This is one reason why RHEL doesn't have a RPM macro with only the
flags. The %{gobuild} RPM macro includes the entire 'go build ...'
invocation.
The Go toolchain also doesn't like the LDFLAGS environment variable as
exported by Fedora's %{meson} RPM macro.
exported by RHEL's %{meson} RPM macro, and RHEL's RPM toolchain doesn't
like the compressed DWARF data generated by the Go toolchain.
Note that these flags are meant for every CPU architecture other than
PPC64, and should be kept updated to match Fedora's Go guidelines. Use
PPC64, and should be kept updated to match RHEL's Go guidelines. Use
'rpm --eval "%{gobuild}"' to expand the %{gobuild} macro.
---
src/go-build-wrapper | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/go-build-wrapper b/src/go-build-wrapper
index 515e1d8a0670..013a35e52a1a 100755
index 0d27120da052..f08f3218560a 100755
--- a/src/go-build-wrapper
+++ b/src/go-build-wrapper
@@ -27,5 +27,6 @@ if ! cd "$1"; then
@ -32,8 +33,8 @@ index 515e1d8a0670..013a35e52a1a 100755
-go build -trimpath -ldflags "-extldflags '-Wl,--wrap,pthread_sigmask $4' -linkmode external -X github.com/containers/toolbox/pkg/version.currentVersion=$3" -o "$2/toolbox"
+unset LDFLAGS
+go build -buildmode pie -compiler gc -tags="rpm_crashtraceback ${BUILDTAGS:-}" -ldflags "${LDFLAGS:-} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \n') -extldflags '-Wl,-z,relro -Wl,--as-needed -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,--wrap,pthread_sigmask $4' -linkmode external -X github.com/containers/toolbox/pkg/version.currentVersion=$3" -a -v -x -o "$2/toolbox"
+go build -buildmode pie -compiler gc -tags="rpm_crashtraceback ${BUILDTAGS:-}" -ldflags "${LDFLAGS:-} -compressdwarf=false -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \n') -extldflags '-Wl,-z,relro -Wl,--as-needed -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,--wrap,pthread_sigmask $4' -linkmode external -X github.com/containers/toolbox/pkg/version.currentVersion=$3" -a -v -x -o "$2/toolbox"
exit "$?"
--
2.29.2
2.31.1

View File

@ -0,0 +1,667 @@
From 62a022428231df50637495673354d4fdd2541c1a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20M=C3=ADchal?= <harrymichal@seznam.cz>
Date: Mon, 7 Jun 2021 14:11:27 +0200
Subject: [PATCH 1/7] pkg/podman: Support parsing 'podman pull' spew into a Go
error
This is meant to get a better understanding of a failed 'podman pull'
invocation to understand whether pulling an image requires logging into
the registry or not. Currently, 'podman pull' doesn't have a dedicated
exit code to denote authorization errors, so this is meant to be a
temporary workaround for that.
Parsing the error stream is inherently fragile and tricky because
there's no guarantee that the structure of the messages won't change,
and there's no clear definition of how the messages are laid out.
Therefore, this approach can't be treated as a generic solution for
getting detailed information about failed Podman invocations.
The error stream is used not only for dumping error messages, but also
for showing progress bars. Therefore, all lines are skipped until one
that starts with "Error: " is found. This is a heuristic based on how
Go programs written using the Cobra [1] library tend to report errors.
All subsequent lines are taken together and split around the ": "
sub-string, on the assumption that the ": " sub-string is used when a
new error message is prefixed to an inner error. Each sub-string
created from the split is treated as a potential member of the chain of
errors reported within Podman.
Some real world examples of the 'podman pull' error stream in the case
of authorization errors are:
* With Docker Hub (https://hub.docker.com/):
Trying to pull docker.io/library/foobar:latest...
Error: Error initializing source docker://foobar:latest: Error reading manifest latest in docker.io/library/foobar: errors:
denied: requested access to the resource is denied
unauthorized: authentication required
* With registry.redhat.io:
Trying to pull registry.redhat.io/foobar:latest...
Error: Error initializing source docker://registry.redhat.io/foobar:latest: unable to retrieve auth token: invalid username/password: unauthorized: Please login to the Red Hat Registry using your Customer Portal credentials. Further instructions can be found here: https://access.redhat.com/RegistryAuthentication
[1] https://github.com/spf13/cobra/
https://pkg.go.dev/github.com/spf13/cobra
https://github.com/containers/toolbox/pull/786
https://github.com/containers/toolbox/pull/787
---
src/pkg/podman/error.go | 109 +++++++++++++++++++++++++
src/pkg/podman/error_test.go | 152 +++++++++++++++++++++++++++++++++++
2 files changed, 261 insertions(+)
create mode 100644 src/pkg/podman/error.go
create mode 100644 src/pkg/podman/error_test.go
diff --git a/src/pkg/podman/error.go b/src/pkg/podman/error.go
new file mode 100644
index 000000000000..ea35de8d7ed8
--- /dev/null
+++ b/src/pkg/podman/error.go
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 2021 Red Hat Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package podman
+
+import (
+ "bufio"
+ "bytes"
+ "strings"
+)
+
+// internalError serves for representing errors printed by Podman to stderr
+type internalError struct {
+ errors []string
+}
+
+func (e *internalError) Error() string {
+ if e.errors == nil || len(e.errors) == 0 {
+ return ""
+ }
+
+ var builder strings.Builder
+
+ for i, part := range e.errors {
+ if i != 0 {
+ builder.WriteString(": ")
+ }
+
+ builder.WriteString(part)
+ }
+
+ return builder.String()
+}
+
+// Is lexically compares errors
+//
+// The comparison is done for every part in the error chain not across.
+func (e *internalError) Is(target error) bool {
+ if target == nil {
+ return false
+ }
+
+ if e.errors == nil || len(e.errors) == 0 {
+ return false
+ }
+
+ for _, part := range e.errors {
+ if part == target.Error() {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (e *internalError) Unwrap() error {
+ if e.errors == nil || len(e.errors) <= 1 {
+ return nil
+ }
+
+ return &internalError{e.errors[1:]}
+}
+
+// parseErrorMsg serves for converting error output of Podman into an error
+// that can be further used in Go
+func parseErrorMsg(stderr *bytes.Buffer) error {
+ // Stderr is not used only for error messages but also for things like
+ // progress bars. We're only interested in the error messages.
+
+ var errMsgFound bool
+ var errMsgParts []string
+
+ scanner := bufio.NewScanner(stderr)
+ for scanner.Scan() {
+ line := scanner.Text()
+
+ if strings.HasPrefix(line, "Error: ") {
+ line = strings.TrimPrefix(line, "Error: ")
+ errMsgFound = true
+ }
+
+ if errMsgFound {
+ line = strings.TrimSpace(line)
+ line = strings.Trim(line, ":")
+
+ parts := strings.Split(line, ": ")
+ errMsgParts = append(errMsgParts, parts...)
+ }
+ }
+
+ if !errMsgFound {
+ return nil
+ }
+
+ return &internalError{errMsgParts}
+}
diff --git a/src/pkg/podman/error_test.go b/src/pkg/podman/error_test.go
new file mode 100644
index 000000000000..11652c709bdd
--- /dev/null
+++ b/src/pkg/podman/error_test.go
@@ -0,0 +1,152 @@
+/*
+ * Copyright © 2021 Red Hat Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package podman
+
+import (
+ "bytes"
+ "errors"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestInternalError(t *testing.T) {
+ type expect struct {
+ IsNil bool
+ Error string
+ Search string
+ Wrap []string
+ }
+
+ testCases := []struct {
+ name string
+ input string
+ expect expect
+ }{
+ {
+ name: "Empty",
+ input: "",
+ expect: expect{
+ IsNil: true,
+ Error: "",
+ },
+ },
+ {
+ name: "Text with only a prolog and no error message",
+ input: "There is only a prolog and no error message",
+ expect: expect{
+ IsNil: true,
+ Error: "",
+ },
+ },
+ {
+ name: "Text with only a prolog and no error message",
+ input: "There is only a prolog Error: not an error message",
+ expect: expect{
+ IsNil: true,
+ Error: "",
+ },
+ },
+ {
+ name: "Text with a prolog before the error message",
+ input: `There is a prolog
+Error: an error message`,
+ expect: expect{
+ Error: "an error message",
+ Search: "an error message",
+ },
+ },
+ {
+ name: "Error message with several wrapped errors",
+ input: "Error: level 1: level 2: level 3: level 4",
+ expect: expect{
+ Error: "level 1: level 2: level 3: level 4",
+ Search: "level 4",
+ Wrap: []string{"level 1", "level 2", "level 3", "level 4"},
+ },
+ },
+ {
+ name: "Error message with a bullet list",
+ input: `Error: an error message:
+ err1
+ err2
+ err3`,
+ expect: expect{
+ Error: "an error message: err1: err2: err3",
+ Search: "err2",
+ Wrap: []string{"an error message", "err1", "err2", "err3"},
+ },
+ },
+ {
+ name: "Error message from 'podman pull' - unauthorized (Docker Hub)",
+ input: `Trying to pull docker.io/library/foobar:latest...
+Error: Error initializing source docker://foobar:latest: Error reading manifest latest in docker.io/library/foobar: errors:
+denied: requested access to the resource is denied
+unauthorized: authentication required`,
+ expect: expect{
+ Error: "Error initializing source docker://foobar:latest: Error reading manifest latest in docker.io/library/foobar: errors: denied: requested access to the resource is denied: unauthorized: authentication required",
+ },
+ },
+ {
+ name: "Error message from 'podman pull' - unauthorized (Red Hat Registry)",
+ input: `Trying to pull registry.redhat.io/foobar:latest...
+Error: Error initializing source docker://registry.redhat.io/foobar:latest: unable to retrieve auth token: invalid username/password: unauthorized: Please login to the Red Hat Registry using your Customer Portal credentials. Further instructions can be found here: https://access.redhat.com/RegistryAuthentication
+`,
+ expect: expect{
+ Error: "Error initializing source docker://registry.redhat.io/foobar:latest: unable to retrieve auth token: invalid username/password: unauthorized: Please login to the Red Hat Registry using your Customer Portal credentials. Further instructions can be found here: https://access.redhat.com/RegistryAuthentication",
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ err := parseErrorMsg(bytes.NewBufferString(tc.input))
+
+ if tc.expect.IsNil {
+ assert.Nil(t, err)
+ return
+ } else {
+ assert.NotNil(t, err)
+ }
+
+ errInternal := err.(*internalError)
+ assert.Equal(t, tc.expect.Error, errInternal.Error())
+
+ if tc.expect.Search != "" {
+ assert.True(t, errInternal.Is(errors.New(tc.expect.Search)))
+ }
+
+ if len(tc.expect.Wrap) != 0 {
+ for {
+ assert.Equal(t, len(tc.expect.Wrap), len(errInternal.errors))
+
+ for i, part := range tc.expect.Wrap {
+ assert.Equal(t, part, errInternal.errors[i])
+ }
+
+ err = errInternal.Unwrap()
+ if err == nil {
+ assert.Equal(t, len(tc.expect.Wrap), 1)
+ break
+ }
+ errInternal = err.(*internalError)
+ tc.expect.Wrap = tc.expect.Wrap[1:]
+ }
+ }
+ })
+ }
+}
--
2.31.1
From 146c93b431941d21b3c686734a7b83a737072004 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20M=C3=ADchal?= <harrymichal@seznam.cz>
Date: Sat, 3 Jul 2021 22:06:30 +0200
Subject: [PATCH 2/7] pkg/shell: Allow extracting the stderr even when it's
shown to the user
This way the standard error stream of the spawned binaries can be
inspected to get a better understanding of the failure, while still
being shown to the user when run with the '--verbose' flag.
Unfortunately, this breaks the progress bar in 'podman pull' because
the standard error stream is no longer connected to a file descriptor
that's a terminal device.
https://github.com/containers/toolbox/pull/787
https://github.com/containers/toolbox/pull/823
---
src/pkg/shell/shell.go | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/src/pkg/shell/shell.go b/src/pkg/shell/shell.go
index 272dcc9ca693..c63b85bc8745 100644
--- a/src/pkg/shell/shell.go
+++ b/src/pkg/shell/shell.go
@@ -40,15 +40,12 @@ func Run(name string, stdin io.Reader, stdout, stderr io.Writer, arg ...string)
}
func RunWithExitCode(name string, stdin io.Reader, stdout, stderr io.Writer, arg ...string) (int, error) {
- logLevel := logrus.GetLevel()
- if stderr == nil && logLevel >= logrus.DebugLevel {
- stderr = os.Stderr
- }
+ stderrWrapper := getStderrWrapper(stderr)
cmd := exec.Command(name, arg...)
cmd.Stdin = stdin
cmd.Stdout = stdout
- cmd.Stderr = stderr
+ cmd.Stderr = stderrWrapper
if err := cmd.Run(); err != nil {
if errors.Is(err, exec.ErrNotFound) {
@@ -66,3 +63,18 @@ func RunWithExitCode(name string, stdin io.Reader, stdout, stderr io.Writer, arg
return 0, nil
}
+
+func getStderrWrapper(buffer io.Writer) io.Writer {
+ var stderr io.Writer
+
+ logLevel := logrus.GetLevel()
+ if logLevel < logrus.DebugLevel {
+ stderr = buffer
+ } else if buffer == nil {
+ stderr = os.Stderr
+ } else {
+ stderr = io.MultiWriter(buffer, os.Stderr)
+ }
+
+ return stderr
+}
--
2.31.1
From 5c3249033224c6f107a2d39ab84e519303d74072 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20M=C3=ADchal?= <harrymichal@seznam.cz>
Date: Sun, 4 Jul 2021 18:15:16 +0200
Subject: [PATCH 3/7] pkg/podman: Try to parse the error from 'podman pull'
into a Go error
https://github.com/containers/toolbox/pull/787
---
src/pkg/podman/podman.go | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/pkg/podman/podman.go b/src/pkg/podman/podman.go
index 9099df1eaf2a..8e7d5068fb97 100644
--- a/src/pkg/podman/podman.go
+++ b/src/pkg/podman/podman.go
@@ -228,10 +228,13 @@ func IsToolboxImage(image string) (bool, error) {
// Pull pulls an image
func Pull(imageName string) error {
+ var stderr bytes.Buffer
+
logLevelString := LogLevel.String()
args := []string{"--log-level", logLevelString, "pull", imageName}
- if err := shell.Run("podman", nil, nil, nil, args...); err != nil {
+ if err := shell.Run("podman", nil, nil, &stderr, args...); err != nil {
+ err := parseErrorMsg(&stderr)
return err
}
--
2.31.1
From 4b8b007201cd019909829d73afdcf919753943a3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20M=C3=ADchal?= <harrymichal@seznam.cz>
Date: Sun, 4 Jul 2021 18:16:12 +0200
Subject: [PATCH 4/7] pkg/podman: Add error for 'podman pull' failing due to no
authorization
https://github.com/containers/toolbox/pull/787
---
src/pkg/podman/podman.go | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/pkg/podman/podman.go b/src/pkg/podman/podman.go
index 8e7d5068fb97..521538c9abfb 100644
--- a/src/pkg/podman/podman.go
+++ b/src/pkg/podman/podman.go
@@ -19,6 +19,7 @@ package podman
import (
"bytes"
"encoding/json"
+ "errors"
"fmt"
"io"
@@ -32,7 +33,8 @@ var (
)
var (
- LogLevel = logrus.ErrorLevel
+ ErrUnauthorized = errors.New("unauthorized")
+ LogLevel = logrus.ErrorLevel
)
// CheckVersion compares provided version with the version of Podman.
--
2.31.1
From ef3bebac89cd833a663dc63fffba8b04ca944dde Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20M=C3=ADchal?= <harrymichal@seznam.cz>
Date: Sat, 3 Jul 2021 02:25:49 +0200
Subject: [PATCH 5/7] pkg/podman: Wrap 'podman login'
https://github.com/containers/toolbox/pull/787
---
src/pkg/podman/podman.go | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/src/pkg/podman/podman.go b/src/pkg/podman/podman.go
index 521538c9abfb..8538bd7c617a 100644
--- a/src/pkg/podman/podman.go
+++ b/src/pkg/podman/podman.go
@@ -228,6 +228,18 @@ func IsToolboxImage(image string) (bool, error) {
return true, nil
}
+func Login(registry, username, password string) error {
+ logLevelString := LogLevel.String()
+ args := []string{"--log-level", logLevelString, "login", registry, "--password-stdin", "--username", username}
+ stdin := bytes.NewBufferString(password)
+
+ if err := shell.Run("podman", stdin, nil, nil, args...); err != nil {
+ return err
+ }
+
+ return nil
+}
+
// Pull pulls an image
func Pull(imageName string) error {
var stderr bytes.Buffer
--
2.31.1
From 49cd3c48c26d37c85aba5dbdcf04a995593ae673 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <rishi@fedoraproject.org>
Date: Sun, 4 Jul 2021 18:11:04 +0200
Subject: [PATCH 6/7] cmd/create: Split out the spinner around 'podman pull'
A subsequent commit will use this when retrying the 'podman pull'
after logging the user into the registry for images that require
authorization.
https://github.com/containers/toolbox/pull/787
---
src/cmd/create.go | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/cmd/create.go b/src/cmd/create.go
index e3245b4c5ae3..6a3005f06041 100644
--- a/src/cmd/create.go
+++ b/src/cmd/create.go
@@ -731,6 +731,14 @@ func pullImage(image, release string) (bool, error) {
return false, nil
}
+ if _, err := pullImageWithSpinner(imageFull); err != nil {
+ return false, fmt.Errorf("failed to pull image %s", imageFull)
+ }
+
+ return true, nil
+}
+
+func pullImageWithSpinner(imageFull string) (bool, error) {
logrus.Debugf("Pulling image %s", imageFull)
stdoutFd := os.Stdout.Fd()
@@ -744,7 +752,7 @@ func pullImage(image, release string) (bool, error) {
}
if err := podman.Pull(imageFull); err != nil {
- return false, fmt.Errorf("failed to pull image %s", imageFull)
+ return false, err
}
return true, nil
--
2.31.1
From 19bb0f08118536c32ff2d2f571d92758dff00dcb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20M=C3=ADchal?= <harrymichal@seznam.cz>
Date: Sun, 4 Jul 2021 18:11:28 +0200
Subject: [PATCH 7/7] cmd/create: Support logging into a registry if necessary
Some registries contain private repositories of images and require the
user to log in first to gain access. With this Toolbox tries to
recognize errors when pulling images and offers the user the means to
log in.
Some changes by Debarshi Ray.
https://github.com/containers/toolbox/pull/787
---
src/cmd/create.go | 72 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 71 insertions(+), 1 deletion(-)
diff --git a/src/cmd/create.go b/src/cmd/create.go
index 6a3005f06041..7cf03e8a4cd2 100644
--- a/src/cmd/create.go
+++ b/src/cmd/create.go
@@ -17,6 +17,7 @@
package cmd
import (
+ "bufio"
"errors"
"fmt"
"os"
@@ -668,6 +669,65 @@ func isPathReadWrite(path string) (bool, error) {
return false, nil
}
+func logIntoRegistry(imageFull, registry string) (bool, error) {
+ fmt.Printf("Image %s requires log-in.\n", imageFull)
+
+ scanner := bufio.NewScanner(os.Stdin)
+
+ stdinFd := os.Stdin.Fd()
+ stdinFdInt := int(stdinFd)
+
+ if terminal.IsTerminal(stdinFdInt) {
+ fmt.Printf("Username: ")
+ }
+
+ if !scanner.Scan() {
+ if err := scanner.Err(); err != nil {
+ logrus.Debugf("Logging into registry: failed to read username: %s", err)
+ }
+
+ return false, errors.New("failed to read username")
+ }
+
+ username := scanner.Text()
+
+ var password string
+
+ if terminal.IsTerminal(stdinFdInt) {
+ logrus.Debug("Reading password from a terminal input")
+
+ fmt.Printf("Password: ")
+
+ passwordBytes, err := terminal.ReadPassword(stdinFdInt)
+ if err != nil {
+ logrus.Debugf("Logging into registry: failed to read password: %s", err)
+ return false, errors.New("failed to read password")
+ }
+
+ password = string(passwordBytes)
+ fmt.Println("")
+ } else {
+ logrus.Debug("Reading password from a non-terminal input")
+
+ if !scanner.Scan() {
+ if err := scanner.Err(); err != nil {
+ logrus.Debugf("Logging into registry: failed to read password: %s", err)
+ }
+
+ return false, errors.New("failed to read password")
+ }
+
+ password = scanner.Text()
+ }
+
+ if err := podman.Login(registry, username, password); err != nil {
+ logrus.Debugf("Logging into registry %s failed: %s", registry, err)
+ return false, fmt.Errorf("failed to log into registry %s", registry)
+ }
+
+ return true, nil
+}
+
func pullImage(image, release string) (bool, error) {
if _, err := utils.ImageReferenceCanBeID(image); err == nil {
logrus.Debugf("Looking for image %s", image)
@@ -732,7 +792,17 @@ func pullImage(image, release string) (bool, error) {
}
if _, err := pullImageWithSpinner(imageFull); err != nil {
- return false, fmt.Errorf("failed to pull image %s", imageFull)
+ if !errors.Is(err, podman.ErrUnauthorized) {
+ return false, fmt.Errorf("failed to pull image %s", imageFull)
+ }
+
+ if _, err := logIntoRegistry(imageFull, domain); err != nil {
+ return false, err
+ }
+
+ if _, err := pullImageWithSpinner(imageFull); err != nil {
+ return false, fmt.Errorf("failed to pull image %s", imageFull)
+ }
}
return true, nil
--
2.31.1

View File

@ -0,0 +1,123 @@
From 6c86cabbe5da6e542b50c5c043b4d213c6279bbc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20M=C3=ADchal?= <harrymichal@seznam.cz>
Date: Fri, 25 Jun 2021 16:04:52 +0200
Subject: [PATCH] cmd/root: Make 'toolbox' create or fall back to a container
if possible
This makes 'toolbox', without any commands specified, behave a lot like
'toolbox enter'. When there aren't any toolbox containers, it will
offer to create a new container matching the same parameters passed to
the command. If there's just one toolbox container available, then it
will fall back to it.
This makes the command line interface a lot similar to that of
github.com/coreos/toolbox, which makes things easier for those
switching over from it.
Some changes by Debarshi Ray.
https://github.com/containers/toolbox/pull/811
---
src/cmd/root.go | 65 +++++++++++++++++++++++++++++++++------
test/system/002-help.bats | 8 -----
2 files changed, 55 insertions(+), 18 deletions(-)
diff --git a/src/cmd/root.go b/src/cmd/root.go
index d50135b9e963..7c4aef61eee8 100644
--- a/src/cmd/root.go
+++ b/src/cmd/root.go
@@ -177,17 +177,62 @@ func rootHelp(cmd *cobra.Command, args []string) {
}
func rootRun(cmd *cobra.Command, args []string) error {
- var builder strings.Builder
- fmt.Fprintf(&builder, "missing command\n")
- fmt.Fprintf(&builder, "\n")
- fmt.Fprintf(&builder, "create Create a new toolbox container\n")
- fmt.Fprintf(&builder, "enter Enter an existing toolbox container\n")
- fmt.Fprintf(&builder, "list List all existing toolbox containers and images\n")
- fmt.Fprintf(&builder, "\n")
- fmt.Fprintf(&builder, "Run '%s --help' for usage.", executableBase)
+ if len(args) != 0 {
+ panic("unexpected argument: commands known or unknown shouldn't reach here")
+ }
- errMsg := builder.String()
- return errors.New(errMsg)
+ if utils.IsInsideContainer() {
+ if !utils.IsInsideToolboxContainer() {
+ return errors.New("this is not a toolbox container")
+ }
+
+ if _, err := utils.ForwardToHost(); err != nil {
+ return err
+ }
+
+ return nil
+ }
+
+ container, image, release, err := utils.ResolveContainerAndImageNames("", "", "", "")
+ if err != nil {
+ return err
+ }
+
+ userShell := os.Getenv("SHELL")
+ if userShell == "" {
+ return errors.New("failed to get the current user's default shell")
+ }
+
+ command := []string{userShell, "-l"}
+
+ hostID, err := utils.GetHostID()
+ if err != nil {
+ return fmt.Errorf("failed to get the host ID: %w", err)
+ }
+
+ hostVariantID, err := utils.GetHostVariantID()
+ if err != nil {
+ return errors.New("failed to get the host VARIANT_ID")
+ }
+
+ var emitEscapeSequence bool
+
+ if hostID == "fedora" && (hostVariantID == "silverblue" || hostVariantID == "workstation") {
+ emitEscapeSequence = true
+ }
+
+ if err := runCommand(container,
+ true,
+ image,
+ release,
+ command,
+ emitEscapeSequence,
+ true,
+ false); err != nil {
+ return err
+ }
+
+ return nil
}
func rootUsage(cmd *cobra.Command) error {
diff --git a/test/system/002-help.bats b/test/system/002-help.bats
index 8a057ddb3818..4ff02c6215e7 100644
--- a/test/system/002-help.bats
+++ b/test/system/002-help.bats
@@ -4,14 +4,6 @@ load 'libs/bats-support/load'
load 'libs/bats-assert/load'
load 'libs/helpers.bash'
-@test "help: Try to run toolbox with no command (shows usage screen)" {
- run $TOOLBOX
-
- assert_failure
- assert_line --index 0 "Error: missing command"
- assert_output --partial "Run 'toolbox --help' for usage."
-}
-
@test "help: Run command 'help'" {
run $TOOLBOX help
--
2.31.1

View File

@ -1,11 +1,16 @@
# RHEL's RPM toolchain doesn't like the compressed DWARF data generated by the
# Go toolchain.
%global _dwz_low_mem_die_limit 0
%global _find_debuginfo_dwz_opts %{nil}
Name: toolbox
Version: 0.0.99.2
%global goipath github.com/containers/%{name}
%gometa
Release: 1%{?dist}
Summary: Tool for containerized command line environments on Linux
Release: 2%{?dist}
Summary: Unprivileged development environment
License: ASL 2.0
URL: https://github.com/containers/%{name}
@ -16,12 +21,20 @@ URL: https://github.com/containers/%{name}
# $ go mod vendor
Source0: %{name}-%{version}-vendored.tar.xz
# Upstream
Patch0: toolbox-cmd-root-Make-toolbox-create-or-fall-back-to-a-conta.patch
# RHEL specific
Patch100: toolbox-Make-the-build-flags-match-RHEL-s-gobuild.patch
Patch101: toolbox-Make-the-build-flags-match-RHEL-s-gobuild-for-PPC64.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1940054
Patch102: toolbox-Support-logging-into-a-registry-if-necessary.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1905383
ExcludeArch: %{ix86}
BuildRequires: golang >= 1.13
BuildRequires: golang-github-cpuguy83-md2man
BuildRequires: go-md2man
BuildRequires: meson
BuildRequires: pkgconfig(bash-completion)
BuildRequires: systemd
@ -47,18 +60,33 @@ The %{name}-tests package contains system tests for %{name}.
%prep
%setup -q
%patch0 -p1
%ifnarch ppc64
%patch100 -p1
%else
%patch101 -p1
%endif
%gomkdir
%patch102 -p1
# %%gomkdir is absent from RHEL 8.
GOBUILDDIR="$(pwd)/_build"
GOSOURCEDIR="$(pwd)"
if [[ ! -e "$GOBUILDDIR/bin" ]] ; then
install -m 0755 -vd "$GOBUILDDIR/bin"
fi
if [[ ! -e "$GOBUILDDIR/src/%{goipath}" ]] ; then
install -m 0755 -vd "$(dirname $GOBUILDDIR/src/%{goipath})"
ln -fs "$GOSOURCEDIR" "$GOBUILDDIR/src/%{goipath}"
fi
cd "$GOBUILDDIR/src/%{goipath}"
%build
export GO111MODULE=off
export GOPATH=%{gobuilddir}:%{gopath}
GOBUILDDIR="$(pwd)/_build"
export GOPATH="$GOBUILDDIR:%{gopath}"
export CGO_CFLAGS="%{optflags} -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64"
ln -s src/cmd cmd
ln -s src/pkg pkg
@ -86,6 +114,12 @@ ln -s src/vendor vendor
%changelog
* Mon Jul 05 2021 Jindrich Novy <jnovy@redhat.com> - 0.0.99.2-2
- Actually apply the patch to make 'toolbox' create or fall back to a
container if possible
- Support logging into a registry if necessary
- Resolves: #1977343
* Fri Jul 02 2021 Jindrich Novy <jnovy@redhat.com> - 0.0.99.2-1
- update to 0.99.2
- Resolves: #1977343