Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 66 additions & 14 deletions pkg/build/builder/daemonless.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ import (
s2ifs "github.com/openshift/source-to-image/pkg/util/fs"
)

const (
defaultMountStart = "/run/secrets"
Comment thread
gabemontero marked this conversation as resolved.
repoFile = "redhat.repo"
subMgrCertDir = "rhsm"
etcPkiEntitle = "etc-pki-entitlement"
)

var (
nodeCredentialsFile = "/var/lib/kubelet/config.json"
)
Expand Down Expand Up @@ -305,40 +312,85 @@ func buildDaemonlessImage(sc types.SystemContext, store storage.Store, isolation

func generateTransientMounts() []string {
mounts := []string{}
mounts = appendRHSMMount(mounts)
mounts = appendRHSMMount(defaultMountStart, mounts)
Comment thread
gabemontero marked this conversation as resolved.
mounts = appendETCPKIMount(defaultMountStart, mounts)
mounts = appendRHRepoMount(defaultMountStart, mounts)
mounts = appendCATrustMount(mounts)
return mounts
}

func appendRHSMMount(mounts []string) []string {
st, err := os.Stat("/run/secrets/rhsm")
func appendRHRepoMount(pathStart string, mounts []string) []string {
Comment thread
gabemontero marked this conversation as resolved.
path := filepath.Join(pathStart, repoFile)
st, err := os.Stat(path)
if err != nil {
log.V(0).Infof("Red Hat entitlements will not be available in this build: failed to stat RHSM secrets directory /run/secrets/rhsm: %v", err)
// since the presence of the repo file is not a given, we won't log this a V(0)
log.V(4).Infof("Failed to stat %s, falling back to the Red Hat yum repository configuration in the build's base image. Error: %v", path, err)
return mounts
}
if !st.IsDir() {
log.V(0).Infof("Red Hat entitlements will not be available in this build: rhsm secrets location /run/secrets/rhsm is not a directory")
if !st.Mode().IsRegular() {
// if the file is there, but an unexpected type, then always have log show up via V(0)
log.V(0).Infof("Falling back to the Red Hat yum repository configuration in the build's base image: %s secrets location %s is a directory.", repoFile, path)
return mounts
}

// Add a bind of /run/secrets/rhsm, to pass along anything that the
// runtime mounted from the node into our /run/secrets/rhsm.
log.V(0).Infof("Adding transient rw bind mount for /run/secrets/rhsm")
tmpDir, err := ioutil.TempDir("/tmp", "rhsm-copy")
// Add a bind of repo file, to pass along anything that the runtime mounted from the node
log.V(0).Infof("Adding transient rw bind mount for %s", path)
tmpDir, err := ioutil.TempDir("/tmp", repoFile+"-copy")
if err != nil {
log.V(0).Infof("Red Hat entitlements will not be available in this build: failed to create tmpdir for rhsm secrets: %v", err)
log.V(0).Infof("Falling back to the Red Hat yum repository configuration in the base image: failed to create tmpdir for %s secret: %v", repoFile, err)
return mounts
}
fs := s2ifs.NewFileSystem()
err = fs.CopyContents("/run/secrets/rhsm", tmpDir, map[string]string{})
err = fs.Copy(path, filepath.Join(tmpDir, repoFile), map[string]string{})
if err != nil {
log.V(0).Infof("Red Hat entitlements will not be available in this build: failed to copy rhsm secrets: %v", err)
log.V(0).Infof("Falling back to the Red Hat yum repository configuration in the base image: failed to copy %s secret: %v", repoFile, err)
return mounts
}
mounts = append(mounts, fmt.Sprintf("%s:/run/secrets/rhsm:rw,nodev,noexec,nosuid", tmpDir))
mounts = append(mounts, fmt.Sprintf("%s:/run/secrets/%s:rw,nodev,noexec,nosuid", filepath.Join(tmpDir, repoFile), repoFile))
return mounts
}

func coreAppendSecretLinksToDirs(pathStart, pathEnd string, mounts []string) []string {
path := filepath.Join(pathStart, pathEnd)
st, err := os.Stat(path)
if err != nil {
// since the presence of dir secret is not a given, we won't log this a V(0)
log.V(0).Infof("Red Hat subscription content will not be available in this build: failed to stat directory %s: %v", path, err)
return mounts
}
if !st.IsDir() && st.Mode()&os.ModeSymlink == 0 {
// if the file is there, but an unexpected type, then always have log show up via V(0)
log.V(0).Infof("Red Hat subscription content will not be available in this build: %s is not a directory", path)
return mounts
}

// Add a bind of dir secret, to pass along anything that the runtime mounted from the node
log.V(0).Infof("Adding transient rw bind mount for %s", path)
tmpDir, err := ioutil.TempDir("/tmp", pathEnd+"-copy")
if err != nil {
log.V(0).Infof("Red Hat subscription content will not be available in this build: failed to create tmpdir for %s secrets: %v", pathEnd, err)
return mounts
}
fs := s2ifs.NewFileSystem()
err = fs.CopyContents(path, tmpDir, map[string]string{})
if err != nil {
log.V(0).Infof("Red Hat subscription content will not be available in this build: failed to copy %s secrets: %v", pathEnd, err)
return mounts
}
mounts = append(mounts, fmt.Sprintf("%s:/run/secrets/%s:rw,nodev,noexec,nosuid", tmpDir, pathEnd))
return mounts
return mounts
}

func appendETCPKIMount(pathStart string, mounts []string) []string {
return coreAppendSecretLinksToDirs(pathStart, etcPkiEntitle, mounts)

}

func appendRHSMMount(pathStart string, mounts []string) []string {
return coreAppendSecretLinksToDirs(pathStart, subMgrCertDir, mounts)
}

func appendCATrustMount(mounts []string) []string {
mountCAEnv, exists := os.LookupEnv("BUILD_MOUNT_ETC_PKI_CATRUST")
if !exists {
Expand Down
243 changes: 243 additions & 0 deletions pkg/build/builder/daemonless_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package builder

import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"strings"
"testing"
Expand Down Expand Up @@ -224,6 +226,247 @@ func TestParseDropCapabilities(t *testing.T) {
}
}

type appendFunc func(string, []string) []string

func coreTestSubscriptionDirMounts(t *testing.T, path string, fn appendFunc) {
cases := []struct {
name string
mode os.FileMode
exists bool
badLink bool
}{
{
name: "dir",
mode: os.ModeDir,
exists: true,
},
{
name: "good-link",
mode: os.ModeSymlink,
exists: true,
},
{
name: "bad-link",
mode: os.ModeSymlink,
exists: true,
badLink: true,
},
{
name: "normal-file",
exists: true,
},
{
name: "non-existent-file",
exists: false,
},
}
for _, tc := range cases {
tmpDir, err := ioutil.TempDir(os.TempDir(), tc.name)
if err != nil {
t.Fatalf(err.Error())
}
defer os.RemoveAll(tmpDir)
if tc.exists {
switch {
case tc.mode&os.ModeType == 0:
// regular file
_, err = os.Create(filepath.Join(tmpDir, path))
if err != nil {
t.Fatalf(err.Error())
}

case tc.mode&os.ModeDir != 0:
// dir
err = os.Mkdir(filepath.Join(tmpDir, path), 0777)
if err != nil {
t.Fatalf(err.Error())
}
_, err = os.Create(filepath.Join(tmpDir, path, "ca"))
if err != nil {
t.Fatalf(err.Error())
}
case tc.mode&os.ModeSymlink != 0:
// symlink
if tc.badLink {
_, err = os.Create(filepath.Join(tmpDir, path+"-link-destination"))
if err != nil {
t.Fatalf(err.Error())
}
} else {
err = os.Mkdir(filepath.Join(tmpDir, path+"-link-destination"), 0777)
if err != nil {
t.Fatalf(err.Error())
}
_, err = os.Create(filepath.Join(tmpDir, path+"-link-destination", "ca"))
if err != nil {
t.Fatalf(err.Error())
}
}
err = os.Symlink(filepath.Join(tmpDir, path+"-link-destination"), filepath.Join(tmpDir, path))
if err != nil {
t.Fatalf(err.Error())
}
}
mounts := fn(tmpDir, []string{})
if tc.mode.IsRegular() && len(mounts) != 0 {
t.Fatalf("bad mounts len %d for %s", len(mounts), tc.name)
}
if tc.badLink && len(mounts) != 0 {
t.Fatalf("bad mounts len %d for %s", len(mounts), tc.name)
}
if tc.badLink {
continue
}
if tc.mode.IsRegular() {
continue
}
if len(mounts) != 1 {
t.Fatalf("bad mounts len %d for %s", len(mounts), tc.name)
}
splitMount := strings.Split(mounts[0], ":")
if len(splitMount) > 0 {
copyDir := splitMount[0]
files, err := ioutil.ReadDir(copyDir)
if err != nil {
t.Fatalf(err.Error())
}
found := false
for _, file := range files {
if file.Name() == "ca" {
found = true
break
}
}
os.RemoveAll(splitMount[0])
if !found {
t.Fatalf("did not find ca in copy")
}
} else {
t.Fatalf("bad mount string for %s: %s", tc.name, mounts[0])
}
} else {
mounts := fn(filepath.Join(tmpDir, "does-not-exist"), []string{})
if len(mounts) != 0 {
t.Fatalf("returned mount when it did not exist")
}
}

}

}

func TestETCPKIMount(t *testing.T) {
coreTestSubscriptionDirMounts(t, "etc-pki-entitlement", appendETCPKIMount)
}

func TestRHSMMount(t *testing.T) {
coreTestSubscriptionDirMounts(t, "rhsm", appendRHSMMount)
}

func TestRHRepoMount(t *testing.T) {
path := "redhat.repo"
cases := []struct {
name string
mode os.FileMode
exists bool
badLink bool
}{
{
name: "dir",
mode: os.ModeDir,
exists: true,
},
{
name: "good-link",
mode: os.ModeSymlink,
exists: true,
},
{
name: "bad-link",
mode: os.ModeSymlink,
exists: true,
badLink: true,
},
{
name: "normal-file",
exists: true,
},
{
name: "non-existent-file",
exists: false,
},
}
for _, tc := range cases {
tmpDir, err := ioutil.TempDir(os.TempDir(), tc.name)
if err != nil {
t.Fatalf(err.Error())
}
defer os.RemoveAll(tmpDir)
if tc.exists {
switch {
case tc.mode&os.ModeType == 0:
// regular file
_, err = os.Create(filepath.Join(tmpDir, path))
if err != nil {
t.Fatalf(err.Error())
}

case tc.mode&os.ModeDir != 0:
// dir
err = os.Mkdir(filepath.Join(tmpDir, path), 0777)
if err != nil {
t.Fatalf(err.Error())
}
case tc.mode&os.ModeSymlink != 0:
// symlink
if tc.badLink {
err = os.Mkdir(filepath.Join(tmpDir, path+"-link-destination"), 0777)
if err != nil {
t.Fatalf(err.Error())
}
} else {
_, err = os.Create(filepath.Join(tmpDir, path+"-link-destination"))
if err != nil {
t.Fatalf(err.Error())
}
}
err = os.Symlink(filepath.Join(tmpDir, path+"-link-destination"), filepath.Join(tmpDir, path))
if err != nil {
t.Fatalf(err.Error())
}
}
mounts := appendRHRepoMount(tmpDir, []string{})
if tc.mode.IsDir() && len(mounts) != 0 {
t.Fatalf("bad mounts len %d for %s", len(mounts), tc.name)
}
if tc.badLink && len(mounts) != 0 {
t.Fatalf("bad mounts len %d for %s", len(mounts), tc.name)
}
if tc.badLink {
continue
}
if tc.mode.IsDir() {
continue
}
if len(mounts) != 1 {
t.Fatalf("bad mounts len %d for %s", len(mounts), tc.name)
}
splitMount := strings.Split(mounts[0], ":")
if len(splitMount) > 0 {
os.RemoveAll(splitMount[0])
} else {
t.Fatalf("bad mount string for %s: %s", tc.name, mounts[0])
}
} else {
mounts := appendRHRepoMount(filepath.Join(tmpDir, "does-not-exist"), []string{})
if len(mounts) != 0 {
t.Fatalf("returned mount when it did not exist")
}
}

}
}

func TestAppendCATrustMount(t *testing.T) {
cases := []struct {
name string
Expand Down