Skip to content

Commit

Permalink
add other implementations
Browse files Browse the repository at this point in the history
Signed-off-by: jason yang <jasonyangshadow@gmail.com>
  • Loading branch information
JasonYangShadow committed Apr 10, 2024
1 parent d1afd97 commit a971357
Show file tree
Hide file tree
Showing 19 changed files with 527 additions and 257 deletions.
6 changes: 4 additions & 2 deletions cmd/internal/cli/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ func init() {
cmdManager.RegisterFlagForCmd(&registryLoginUsernameFlag, RegistryLoginCmd)
cmdManager.RegisterFlagForCmd(&registryLoginPasswordFlag, RegistryLoginCmd)
cmdManager.RegisterFlagForCmd(&registryLoginPasswordStdinFlag, RegistryLoginCmd)
cmdManager.RegisterFlagForCmd(&commonAuthFileFlag, RegistryLoginCmd)
cmdManager.RegisterFlagForCmd(&commonAuthFileFlag, RegistryLogoutCmd)
})
}

Expand All @@ -91,7 +93,7 @@ var RegistryCmd = &cobra.Command{
var RegistryLoginCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
if err := apptainer.RegistryLogin(remoteConfig, ObtainLoginArgs(args[0])); err != nil {
if err := apptainer.RegistryLogin(remoteConfig, ObtainLoginArgs(args[0]), reqAuthFile); err != nil {
sylog.Fatalf("%s", err)
}
},
Expand All @@ -114,7 +116,7 @@ var RegistryLogoutCmd = &cobra.Command{
name = args[0]
}

if err := apptainer.RegistryLogout(remoteConfig, name); err != nil {
if err := apptainer.RegistryLogout(remoteConfig, name, reqAuthFile); err != nil {
sylog.Fatalf("%s", err)
}
sylog.Infof("Logout succeeded")
Expand Down
9 changes: 6 additions & 3 deletions cmd/internal/cli/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ func init() {

cmdManager.RegisterFlagForCmd(&remoteKeyserverOrderFlag, RemoteAddKeyserverCmd)
cmdManager.RegisterFlagForCmd(&remoteKeyserverInsecureFlag, RemoteAddKeyserverCmd)

cmdManager.RegisterFlagForCmd(&commonAuthFileFlag, RemoteLoginCmd)
cmdManager.RegisterFlagForCmd(&commonAuthFileFlag, RemoteLogoutCmd)
})
}

Expand Down Expand Up @@ -306,7 +309,7 @@ var RemoteAddCmd = &cobra.Command{
Name: name,
Tokenfile: loginTokenFile,
}
if err := apptainer.RemoteLogin(remoteConfig, loginArgs); err != nil {
if err := apptainer.RemoteLogin(remoteConfig, loginArgs, reqAuthFile); err != nil {
sylog.Fatalf("%s", err)
}
}
Expand Down Expand Up @@ -402,7 +405,7 @@ var RemoteLoginCmd = &cobra.Command{
loginArgs.Password = strings.TrimSuffix(loginArgs.Password, "\r")
}

if err := apptainer.RemoteLogin(remoteConfig, loginArgs); err != nil {
if err := apptainer.RemoteLogin(remoteConfig, loginArgs, reqAuthFile); err != nil {
sylog.Fatalf("%s", err)
}
},
Expand All @@ -425,7 +428,7 @@ var RemoteLogoutCmd = &cobra.Command{
name = args[0]
}

if err := apptainer.RemoteLogout(remoteConfig, name); err != nil {
if err := apptainer.RemoteLogout(remoteConfig, name, reqAuthFile); err != nil {
sylog.Fatalf("%s", err)
}
sylog.Infof("Logout succeeded")
Expand Down
128 changes: 128 additions & 0 deletions e2e/actions/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -3012,6 +3012,133 @@ func (c actionTests) relWorkdirScratch(t *testing.T) {
}
}

// actionAuth tests run/exec/shell flows that involve authenticated pulls from
// OCI registries.
func (c actionTests) actionAuth(t *testing.T) {
profiles := []e2e.Profile{
e2e.UserProfile,
e2e.RootProfile,
e2e.FakerootProfile,
}

for _, p := range profiles {
t.Run(p.String(), func(t *testing.T) {
t.Run("default", func(t *testing.T) {
c.actionAuthTester(t, false, p)
})
t.Run("custom", func(t *testing.T) {
c.actionAuthTester(t, true, p)
})
})
}
}

func (c actionTests) actionAuthTester(t *testing.T, withCustomAuthFile bool, profile e2e.Profile) {
e2e.EnsureImage(t, c.env)

tmpdir, tmpdirCleanup := e2e.MakeTempDir(t, c.env.TestDir, "action-auth", "")
t.Cleanup(func() {
if !t.Failed() {
tmpdirCleanup(t)
}
})

prevCwd, err := os.Getwd()
if err != nil {
t.Fatalf("could not get current working directory: %s", err)
}
defer os.Chdir(prevCwd)
if err = os.Chdir(tmpdir); err != nil {
t.Fatalf("could not change cwd to %q: %s", tmpdir, err)
}

localAuthFileName := ""
if withCustomAuthFile {
localAuthFileName = "./my_local_authfile"
}

authFileArgs := []string{}
if withCustomAuthFile {
authFileArgs = []string{"--authfile", localAuthFileName}
}

t.Cleanup(func() {
e2e.PrivateRepoLogout(t, c.env, e2e.UserProfile, localAuthFileName)
})

orasCustomPushTarget := fmt.Sprintf(
"oras://%s/authfile-%s-oras-alpine:latest",
c.env.TestRegistryPrivPath, strings.ToLower(profile.String()),
)

tests := []struct {
name string
cmd string
args []string
whileLoggedIn bool
expectExit int
}{
{
name: "docker before auth",
cmd: "exec",
args: []string{"--disable-cache", "--no-https", c.env.TestRegistryPrivImage, "true"},
whileLoggedIn: false,
expectExit: 255,
},
{
name: "docker",
cmd: "exec",
args: []string{"--disable-cache", "--no-https", c.env.TestRegistryPrivImage, "true"},
whileLoggedIn: true,
expectExit: 0,
},
{
name: "noauth docker",
cmd: "exec",
args: []string{"--disable-cache", "--no-https", c.env.TestRegistryPrivImage, "true"},
whileLoggedIn: false,
expectExit: 255,
},
{
name: "oras push",
cmd: "push",
args: []string{c.env.ImagePath, orasCustomPushTarget},
whileLoggedIn: true,
expectExit: 0,
},
{
name: "noauth oras",
cmd: "exec",
args: []string{"--disable-cache", "--no-https", orasCustomPushTarget, "true"},
whileLoggedIn: false,
expectExit: 255,
},
{
name: "oras",
cmd: "exec",
args: []string{"--disable-cache", "--no-https", orasCustomPushTarget, "true"},
whileLoggedIn: true,
expectExit: 0,
},
}

for _, tt := range tests {
if tt.whileLoggedIn {
e2e.PrivateRepoLogin(t, c.env, profile, localAuthFileName)
} else {
e2e.PrivateRepoLogout(t, c.env, profile, localAuthFileName)
}
c.env.RunApptainer(
t,
e2e.AsSubtest(tt.name),
e2e.WithProfile(profile),
e2e.WithCommand(tt.cmd),
e2e.WithArgs(append(authFileArgs, tt.args...)...),
e2e.ExpectExit(tt.expectExit),
)
}
}

// E2ETests is the main func to trigger the test suite
func E2ETests(env e2e.TestEnv) testhelper.Tests {
c := actionTests{
Expand Down Expand Up @@ -3064,5 +3191,6 @@ func E2ETests(env e2e.TestEnv) testhelper.Tests {
"fakeroot home": c.actionFakerootHome, // test home dir in fakeroot
"relWorkdirScratch": np(c.relWorkdirScratch), // test relative --workdir with --scratch
"issue 1868": c.issue1868, // https://github.com/apptainer/apptainer/issues/1868
"auth": np(c.actionAuth), // tests action cmds w/authenticated pulls from OCI registries
}
}
91 changes: 90 additions & 1 deletion e2e/instance/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,92 @@ func (c *ctx) testInstanceFromURI(t *testing.T) {
}
}

// Test that custom auth file authentication works with instance start
func (c *ctx) testInstanceAuthFile(t *testing.T) {
e2e.EnsureORASImage(t, c.env)
instanceName := "actionAuthTesterInstance"
localAuthFileName := "./my_local_authfile"
authFileArgs := []string{"--authfile", localAuthFileName}

tmpdir, tmpdirCleanup := e2e.MakeTempDir(t, c.env.TestDir, "action-auth", "")
t.Cleanup(func() {
if !t.Failed() {
tmpdirCleanup(t)
}
})

prevCwd, err := os.Getwd()
if err != nil {
t.Fatalf("could not get current working directory: %s", err)
}
defer os.Chdir(prevCwd)
if err = os.Chdir(tmpdir); err != nil {
t.Fatalf("could not change cwd to %q: %s", tmpdir, err)
}

tests := []struct {
name string
subCmd string
args []string
whileLoggedIn bool
expectExit int
}{
{
name: "start before auth",
subCmd: "start",
args: append(authFileArgs, "--disable-cache", "--no-https", c.env.TestRegistryPrivImage, instanceName),
whileLoggedIn: false,
expectExit: 255,
},
{
name: "start",
subCmd: "start",
args: append(authFileArgs, "--disable-cache", "--no-https", c.env.TestRegistryPrivImage, instanceName),
whileLoggedIn: true,
expectExit: 0,
},
{
name: "stop",
subCmd: "stop",
args: []string{instanceName},
whileLoggedIn: true,
expectExit: 0,
},
{
name: "start noauth",
subCmd: "start",
args: append(authFileArgs, "--disable-cache", "--no-https", c.env.TestRegistryPrivImage, instanceName),
whileLoggedIn: false,
expectExit: 255,
},
}

profiles := []e2e.Profile{
e2e.UserProfile,
e2e.RootProfile,
}

for _, p := range profiles {
t.Run(p.String(), func(t *testing.T) {
for _, tt := range tests {
if tt.whileLoggedIn {
e2e.PrivateRepoLogin(t, c.env, e2e.UserProfile, localAuthFileName)
} else {
e2e.PrivateRepoLogout(t, c.env, e2e.UserProfile, localAuthFileName)
}
c.env.RunApptainer(
t,
e2e.AsSubtest(tt.name),
e2e.WithProfile(e2e.UserProfile),
e2e.WithCommand("instance "+tt.subCmd),
e2e.WithArgs(tt.args...),
e2e.ExpectExit(tt.expectExit),
)
}
})
}
}

// Execute an instance process, kill master process
// and try to start another instance with same name
func (c *ctx) testGhostInstance(t *testing.T) {
Expand Down Expand Up @@ -455,6 +541,8 @@ func E2ETests(env e2e.TestEnv) testhelper.Tests {
env: env,
}

np := testhelper.NoParallel

return testhelper.Tests{
"ordered": func(t *testing.T) {
c := &ctx{
Expand Down Expand Up @@ -496,6 +584,7 @@ func E2ETests(env e2e.TestEnv) testhelper.Tests {
})
}
},
"issue 5033": c.issue5033, // https://github.com/apptainer/singularity/issues/4836
"issue 5033": c.issue5033, // https://github.com/apptainer/singularity/issues/4836
"auth": np(c.testInstanceAuthFile), // custom --authfile with instance start command
}
}
18 changes: 2 additions & 16 deletions e2e/internal/e2e/dockerhub_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@
package e2e

import (
"encoding/json"
"os"
"path/filepath"
"testing"

"github.com/apptainer/apptainer/internal/pkg/remote/credential/ociauth"
"github.com/apptainer/apptainer/internal/pkg/util/user"
"github.com/apptainer/apptainer/pkg/syfs"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/config/types"
)

const dockerHub = "docker.io"
Expand All @@ -45,19 +43,7 @@ func SetupDockerHubCredentials(t *testing.T) {
func writeDockerHubCredentials(t *testing.T, dir, username, pass string) {
configPath := filepath.Join(dir, ".apptainer", syfs.DockerConfFile)

cf := configfile.ConfigFile{
AuthConfigs: map[string]types.AuthConfig{
dockerHub: {
Username: username,
Password: pass,
},
},
}

configData, err := json.Marshal(cf)
if err != nil {
if err := ociauth.LoginAndStore(dockerHub, username, pass, false, configPath); err != nil {
t.Error(err)
}

os.WriteFile(configPath, configData, 0o600)
}
34 changes: 19 additions & 15 deletions e2e/internal/e2e/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,23 @@ package e2e
// from specifying which Apptainer binary to use to controlling how Apptainer
// environment variables will be set.
type TestEnv struct {
CmdPath string // Path to the Apptainer binary to use for the execution of an Apptainer command
ImagePath string // Path to the image that has to be used for the execution of an Apptainer command
SingularityImagePath string // Path to a Singularity image for legacy tests
DebianImagePath string // Path to an image containing a Debian distribution with libc compatible to the host libc
OrasTestImage string // URI to SIF image pushed into local registry with ORAS
TestDir string // Path to the directory from which an Apptainer command needs to be executed
TestRegistry string // Host:Port of local registry
TestRegistryImage string // URI to OCI image pushed into local registry
HomeDir string // HomeDir sets the home directory that will be used for the execution of a command
KeyringDir string // KeyringDir sets the directory where the keyring will be created for the execution of a command (instead of using APPTAINER_KEYSDIR which should be avoided when running e2e tests)
PrivCacheDir string // PrivCacheDir sets the location of the image cache to be used by the Apptainer command to be executed as root (instead of using APPTAINER_CACHE_DIR which should be avoided when running e2e tests)
UnprivCacheDir string // UnprivCacheDir sets the location of the image cache to be used by the Apptainer command to be executed as the unpriv user (instead of using APPTAINER_CACHE_DIR which should be avoided when running e2e tests)
RunDisabled bool
DisableCache bool // DisableCache can be set to disable the cache during the execution of a e2e command
InsecureRegistry string // Insecure registry replaced with nip.io
CmdPath string // Path to the Apptainer binary to use for the execution of an Apptainer command
ImagePath string // Path to the image that has to be used for the execution of an Apptainer command
SingularityImagePath string // Path to a Singularity image for legacy tests
DebianImagePath string // Path to an image containing a Debian distribution with libc compatible to the host libc
OrasTestImage string // URI to SIF image pushed into local registry with ORAS
TestDir string // Path to the directory from which an Apptainer command needs to be executed
TestRegistry string // Host:Port of local registry
TestRegistryImage string // URI to OCI image pushed into local registry
HomeDir string // HomeDir sets the home directory that will be used for the execution of a command
KeyringDir string // KeyringDir sets the directory where the keyring will be created for the execution of a command (instead of using APPTAINER_KEYSDIR which should be avoided when running e2e tests)
PrivCacheDir string // PrivCacheDir sets the location of the image cache to be used by the Apptainer command to be executed as root (instead of using APPTAINER_CACHE_DIR which should be avoided when running e2e tests)
UnprivCacheDir string // UnprivCacheDir sets the location of the image cache to be used by the Apptainer command to be executed as the unpriv user (instead of using APPTAINER_CACHE_DIR which should be avoided when running e2e tests)
RunDisabled bool
DisableCache bool // DisableCache can be set to disable the cache during the execution of a e2e command
InsecureRegistry string // Insecure registry replaced with nip.io
TestRegistryPrivURI string // Transport (docker://) + Host:Port of local registry + path to private location
TestRegistryPrivPath string // Host:Port of local registry + path to private location
TestRegistryPrivImage string // URI to OCI image pushed into private location in local registry
OrasTestPrivImage string // URI to SIF image pushed into local registry with ORAS
}
Loading

0 comments on commit a971357

Please sign in to comment.