Skip to content

Commit

Permalink
Add skopeo login&logout
Browse files Browse the repository at this point in the history
Implements skopeo login&logout commands.

Signed-off-by: Qi Wang <qiwan@redhat.com>
  • Loading branch information
QiWang19 committed May 11, 2020
1 parent 71a14d7 commit 0ec2610
Show file tree
Hide file tree
Showing 173 changed files with 1,039 additions and 27,706 deletions.
47 changes: 47 additions & 0 deletions cmd/skopeo/login.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package main

import (
"io"
"os"

"github.com/containers/common/pkg/auth"
"github.com/containers/image/v5/types"
"github.com/spf13/cobra"
)

type loginOptions struct {
global *globalOptions
loginOpts auth.LoginOptions
getLogin optionalBool
tlsVerify optionalBool
}

func loginCmd(global *globalOptions) *cobra.Command {
opts := loginOptions{
global: global,
}
cmd := &cobra.Command{
Use: "login",
Short: "Login to a container registry",
Long: "Login to a container registry on a specified server.",
RunE: commandAction(opts.run),
Example: `skopeo login quay.io`,
}
adjustUsage(cmd)
flags := cmd.Flags()
optionalBoolFlag(flags, &opts.tlsVerify, "tls-verify", "require HTTPS and verify certificates when accessing the registry")
flags.AddFlagSet(auth.GetLoginFlags(&opts.loginOpts))
return cmd
}

func (opts *loginOptions) run(args []string, stdout io.Writer) error {
ctx, cancel := opts.global.commandTimeoutContext()
defer cancel()
opts.loginOpts.Stdout = stdout
opts.loginOpts.Stdin = os.Stdin
sys := opts.global.newSystemContext()
if opts.tlsVerify.present {
sys.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.tlsVerify.value)
}
return auth.Login(ctx, sys, &opts.loginOpts, args)
}
35 changes: 35 additions & 0 deletions cmd/skopeo/logout.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

import (
"io"

"github.com/containers/common/pkg/auth"
"github.com/spf13/cobra"
)

type logoutOptions struct {
global *globalOptions
logoutOpts auth.LogoutOptions
}

func logoutCmd(global *globalOptions) *cobra.Command {
opts := logoutOptions{
global: global,
}
cmd := &cobra.Command{
Use: "logout",
Short: "Logout of a container registry",
Long: "Logout of a container registry on a specified server.",
RunE: commandAction(opts.run),
Example: `skopeo logout quay.io`,
}
adjustUsage(cmd)
cmd.Flags().AddFlagSet(auth.GetLogoutFlags(&opts.logoutOpts))
return cmd
}

func (opts *logoutOptions) run(args []string, stdout io.Writer) error {
opts.logoutOpts.Stdout = stdout
sys := opts.global.newSystemContext()
return auth.Logout(sys, &opts.logoutOpts, args)
}
21 changes: 21 additions & 0 deletions cmd/skopeo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"time"

"github.com/containers/image/v5/signature"
"github.com/containers/image/v5/types"
"github.com/containers/skopeo/version"
"github.com/containers/storage/pkg/reexec"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -71,6 +72,8 @@ func createApp() (*cobra.Command, *globalOptions) {
deleteCmd(&opts),
inspectCmd(&opts),
layersCmd(&opts),
loginCmd(&opts),
logoutCmd(&opts),
manifestDigestCmd(),
syncCmd(&opts),
standaloneSignCmd(),
Expand Down Expand Up @@ -129,3 +132,21 @@ func (opts *globalOptions) commandTimeoutContext() (context.Context, context.Can
}
return ctx, cancel
}

// newSystemContext returns a *types.SystemContext corresponding to opts.
// It is guaranteed to return a fresh instance, so it is safe to make additional updates to it.
func (opts *globalOptions) newSystemContext() *types.SystemContext {
ctx := &types.SystemContext{
RegistriesDirPath: opts.registriesDirPath,
ArchitectureChoice: opts.overrideArch,
OSChoice: opts.overrideOS,
VariantChoice: opts.overrideVariant,
SystemRegistriesConfPath: opts.registriesConfPath,
BigFilesTemporaryDir: opts.tmpDir,
}
// DEPRECATED: We support this for backward compatibility, but override it if a per-image flag is provided.
if opts.tlsVerify.present {
ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.tlsVerify.value)
}
return ctx
}
31 changes: 31 additions & 0 deletions cmd/skopeo/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package main

import (
"bytes"
"testing"

"github.com/containers/image/v5/types"
"github.com/stretchr/testify/assert"
)

// runSkopeo creates an app object and runs it with args, with an implied first "skopeo".
Expand All @@ -14,3 +18,30 @@ func runSkopeo(args ...string) (string, error) {
err := app.Execute()
return stdout.String(), err
}

func TestGlobalOptionsNewSystemContext(t *testing.T) {
// Default state
opts, _ := fakeGlobalOptions(t, []string{})
res := opts.newSystemContext()
assert.Equal(t, &types.SystemContext{}, res)
// Set everything to non-default values.
opts, _ = fakeGlobalOptions(t, []string{
"--registries.d", "/srv/registries.d",
"--override-arch", "overridden-arch",
"--override-os", "overridden-os",
"--override-variant", "overridden-variant",
"--tmpdir", "/srv",
"--registries-conf", "/srv/registries.conf",
"--tls-verify=false",
})
res = opts.newSystemContext()
assert.Equal(t, &types.SystemContext{
RegistriesDirPath: "/srv/registries.d",
ArchitectureChoice: "overridden-arch",
OSChoice: "overridden-os",
VariantChoice: "overridden-variant",
BigFilesTemporaryDir: "/srv",
SystemRegistriesConfPath: "/srv/registries.conf",
DockerInsecureSkipTLSVerify: types.OptionalBoolTrue,
}, res)
}
26 changes: 8 additions & 18 deletions cmd/skopeo/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,29 +111,20 @@ func imageFlags(global *globalOptions, shared *sharedImageOptions, flagPrefix, c
// newSystemContext returns a *types.SystemContext corresponding to opts.
// It is guaranteed to return a fresh instance, so it is safe to make additional updates to it.
func (opts *imageOptions) newSystemContext() (*types.SystemContext, error) {
ctx := &types.SystemContext{
RegistriesDirPath: opts.global.registriesDirPath,
ArchitectureChoice: opts.global.overrideArch,
OSChoice: opts.global.overrideOS,
VariantChoice: opts.global.overrideVariant,
DockerCertPath: opts.dockerCertPath,
OCISharedBlobDirPath: opts.sharedBlobDir,
AuthFilePath: opts.shared.authFilePath,
DockerDaemonHost: opts.dockerDaemonHost,
DockerDaemonCertPath: opts.dockerCertPath,
SystemRegistriesConfPath: opts.global.registriesConfPath,
BigFilesTemporaryDir: opts.global.tmpDir,
}
// *types.SystemContext instance from globalOptions
// imageOptions option overrides the instance if both are present.
ctx := opts.global.newSystemContext()
ctx.DockerCertPath = opts.dockerCertPath
ctx.OCISharedBlobDirPath = opts.sharedBlobDir
ctx.AuthFilePath = opts.shared.authFilePath
ctx.DockerDaemonHost = opts.dockerDaemonHost
ctx.DockerDaemonCertPath = opts.dockerCertPath
if opts.dockerImageOptions.authFilePath.present {
ctx.AuthFilePath = opts.dockerImageOptions.authFilePath.value
}
if opts.tlsVerify.present {
ctx.DockerDaemonInsecureSkipTLSVerify = !opts.tlsVerify.value
}
// DEPRECATED: We support this for backward compatibility, but override it if a per-image flag is provided.
if opts.global.tlsVerify.present {
ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.global.tlsVerify.value)
}
if opts.tlsVerify.present {
ctx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!opts.tlsVerify.value)
}
Expand Down Expand Up @@ -167,7 +158,6 @@ type imageDestOptions struct {
func imageDestFlags(global *globalOptions, shared *sharedImageOptions, flagPrefix, credsOptionAlias string) (pflag.FlagSet, *imageDestOptions) {
genericFlags, genericOptions := imageFlags(global, shared, flagPrefix, credsOptionAlias)
opts := imageDestOptions{imageOptions: genericOptions}

fs := pflag.FlagSet{}
fs.AddFlagSet(&genericFlags)
fs.BoolVar(&opts.dirForceCompression, flagPrefix+"compress", false, "Compress tarball image layers when saving to directory using the 'dir' transport. (default is same compression type as source)")
Expand Down
29 changes: 29 additions & 0 deletions completions/bash/skopeo
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,33 @@ _skopeo_list_repository_tags() {
_complete_ "$options_with_args" "$boolean_options"
}

_skopeo_login() {
local options_with_args="
--authfile
--cert-dir
--password -p
--username -u
"

local boolean_options="
--get-login
--tls-verify
--password-stdin
"
_complete_ "$options_with_args" "$boolean_options"
}

_skopeo_logout() {
local options_with_args="
--authfile
"

local boolean_options="
--all -a
"
_complete_ "$options_with_args" "$boolean_options"
}

_skopeo_skopeo() {
# XXX: Changes here need to be refleceted in the manually expanded
# string in the `case` statement below as well.
Expand All @@ -182,6 +209,8 @@ _skopeo_skopeo() {
delete
inspect
list-tags
login
logout
manifest-digest
standalone-sign
standalone-verify
Expand Down
101 changes: 101 additions & 0 deletions docs/skopeo-login.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
% skopeo-login(1)

## NAME
skopeo\-login - Login to a container registry

## SYNOPSIS
**skoepo login** [*options*] *registry*

## DESCRIPTION
**skopeo login** logs into a specified registry server with the correct username
and password. **skopeo login** reads in the username and password from STDIN.
The username and password can also be set using the **username** and **password** flags.
The path of the authentication file can be specified by the user by setting the **authfile**
flag. The default path used is **${XDG\_RUNTIME\_DIR}/containers/auth.json**.

## OPTIONS

**--password**, **-p**=*password*

Password for registry

**--password-stdin**

Take the password from stdin

**--username**, **-u**=*username*

Username for registry

**--authfile**=*path*

Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json

Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE
environment variable. `export REGISTRY_AUTH_FILE=path`

**--get-login**

Return the logged-in user for the registry. Return error if no login is found.

**--cert-dir**=*path*

Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry.
Default certificates directory is _/etc/containers/certs.d_.

**--tls-verify**=*true|false*

Require HTTPS and verify certificates when contacting registries (default: true). If explicitly set to true,
then TLS verification will be used. If set to false, then TLS verification will not be used. If not specified,
TLS verification will be used unless the target registry is listed as an insecure registry in registries.conf.

**--help**, **-h**

Print usage statement

## EXAMPLES

```
$ skopeo login docker.io
Username: testuser
Password:
Login Succeeded!
```

```
$ skopeo login -u testuser -p testpassword localhost:5000
Login Succeeded!
```

```
$ skopeo login --authfile authdir/myauths.json docker.io
Username: testuser
Password:
Login Succeeded!
```

```
$ skopeo login --tls-verify=false -u test -p test localhost:5000
Login Succeeded!
```

```
$ skopeo login --cert-dir /etc/containers/certs.d/ -u foo -p bar localhost:5000
Login Succeeded!
```

```
$ skopeo login -u testuser --password-stdin < testpassword.txt docker.io
Login Succeeded!
```

```
$ echo $testpassword | skopeo login -u testuser --password-stdin docker.io
Login Succeeded!
```

## SEE ALSO
skopeo(1), skopeo-logout(1)

## HISTORY
May 2020, Originally compiled by Qi Wang <qiwan@redhat.com>
Loading

0 comments on commit 0ec2610

Please sign in to comment.