github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/internal/test/environment/environment.go (about)

     1  package environment // import "github.com/docker/docker/internal/test/environment"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/docker/docker/api/types"
    11  	"github.com/docker/docker/api/types/filters"
    12  	"github.com/docker/docker/client"
    13  	"github.com/docker/docker/internal/test"
    14  	"github.com/docker/docker/internal/test/fixtures/load"
    15  	"github.com/pkg/errors"
    16  	"gotest.tools/assert"
    17  )
    18  
    19  // Execution contains information about the current test execution and daemon
    20  // under test
    21  type Execution struct {
    22  	client            client.APIClient
    23  	DaemonInfo        types.Info
    24  	OSType            string
    25  	PlatformDefaults  PlatformDefaults
    26  	protectedElements protectedElements
    27  }
    28  
    29  // PlatformDefaults are defaults values for the platform of the daemon under test
    30  type PlatformDefaults struct {
    31  	BaseImage            string
    32  	VolumesConfigPath    string
    33  	ContainerStoragePath string
    34  }
    35  
    36  // New creates a new Execution struct
    37  func New() (*Execution, error) {
    38  	client, err := client.NewClientWithOpts(client.FromEnv)
    39  	if err != nil {
    40  		return nil, errors.Wrapf(err, "failed to create client")
    41  	}
    42  
    43  	info, err := client.Info(context.Background())
    44  	if err != nil {
    45  		return nil, errors.Wrapf(err, "failed to get info from daemon")
    46  	}
    47  
    48  	osType := getOSType(info)
    49  
    50  	return &Execution{
    51  		client:            client,
    52  		DaemonInfo:        info,
    53  		OSType:            osType,
    54  		PlatformDefaults:  getPlatformDefaults(info, osType),
    55  		protectedElements: newProtectedElements(),
    56  	}, nil
    57  }
    58  
    59  func getOSType(info types.Info) string {
    60  	// Docker EE does not set the OSType so allow the user to override this value.
    61  	userOsType := os.Getenv("TEST_OSTYPE")
    62  	if userOsType != "" {
    63  		return userOsType
    64  	}
    65  	return info.OSType
    66  }
    67  
    68  func getPlatformDefaults(info types.Info, osType string) PlatformDefaults {
    69  	volumesPath := filepath.Join(info.DockerRootDir, "volumes")
    70  	containersPath := filepath.Join(info.DockerRootDir, "containers")
    71  
    72  	switch osType {
    73  	case "linux":
    74  		return PlatformDefaults{
    75  			BaseImage:            "scratch",
    76  			VolumesConfigPath:    toSlash(volumesPath),
    77  			ContainerStoragePath: toSlash(containersPath),
    78  		}
    79  	case "windows":
    80  		baseImage := "microsoft/windowsservercore"
    81  		if override := os.Getenv("WINDOWS_BASE_IMAGE"); override != "" {
    82  			baseImage = override
    83  			fmt.Println("INFO: Windows Base image is ", baseImage)
    84  		}
    85  		return PlatformDefaults{
    86  			BaseImage:            baseImage,
    87  			VolumesConfigPath:    filepath.FromSlash(volumesPath),
    88  			ContainerStoragePath: filepath.FromSlash(containersPath),
    89  		}
    90  	default:
    91  		panic(fmt.Sprintf("unknown OSType for daemon: %s", osType))
    92  	}
    93  }
    94  
    95  // Make sure in context of daemon, not the local platform. Note we can't
    96  // use filepath.FromSlash or ToSlash here as they are a no-op on Unix.
    97  func toSlash(path string) string {
    98  	return strings.Replace(path, `\`, `/`, -1)
    99  }
   100  
   101  // IsLocalDaemon is true if the daemon under test is on the same
   102  // host as the test process.
   103  //
   104  // Deterministically working out the environment in which CI is running
   105  // to evaluate whether the daemon is local or remote is not possible through
   106  // a build tag.
   107  //
   108  // For example Windows to Linux CI under Jenkins tests the 64-bit
   109  // Windows binary build with the daemon build tag, but calls a remote
   110  // Linux daemon.
   111  //
   112  // We can't just say if Windows then assume the daemon is local as at
   113  // some point, we will be testing the Windows CLI against a Windows daemon.
   114  //
   115  // Similarly, it will be perfectly valid to also run CLI tests from
   116  // a Linux CLI (built with the daemon tag) against a Windows daemon.
   117  func (e *Execution) IsLocalDaemon() bool {
   118  	return os.Getenv("DOCKER_REMOTE_DAEMON") == ""
   119  }
   120  
   121  // IsRemoteDaemon is true if the daemon under test is on different host
   122  // as the test process.
   123  func (e *Execution) IsRemoteDaemon() bool {
   124  	return !e.IsLocalDaemon()
   125  }
   126  
   127  // DaemonAPIVersion returns the negotiated daemon api version
   128  func (e *Execution) DaemonAPIVersion() string {
   129  	version, err := e.APIClient().ServerVersion(context.TODO())
   130  	if err != nil {
   131  		return ""
   132  	}
   133  	return version.APIVersion
   134  }
   135  
   136  // Print the execution details to stdout
   137  // TODO: print everything
   138  func (e *Execution) Print() {
   139  	if e.IsLocalDaemon() {
   140  		fmt.Println("INFO: Testing against a local daemon")
   141  	} else {
   142  		fmt.Println("INFO: Testing against a remote daemon")
   143  	}
   144  }
   145  
   146  // APIClient returns an APIClient connected to the daemon under test
   147  func (e *Execution) APIClient() client.APIClient {
   148  	return e.client
   149  }
   150  
   151  // IsUserNamespace returns whether the user namespace remapping is enabled
   152  func (e *Execution) IsUserNamespace() bool {
   153  	root := os.Getenv("DOCKER_REMAP_ROOT")
   154  	return root != ""
   155  }
   156  
   157  // HasExistingImage checks whether there is an image with the given reference.
   158  // Note that this is done by filtering and then checking whether there were any
   159  // results -- so ambiguous references might result in false-positives.
   160  func (e *Execution) HasExistingImage(t assert.TestingT, reference string) bool {
   161  	if ht, ok := t.(test.HelperT); ok {
   162  		ht.Helper()
   163  	}
   164  	client := e.APIClient()
   165  	filter := filters.NewArgs()
   166  	filter.Add("dangling", "false")
   167  	filter.Add("reference", reference)
   168  	imageList, err := client.ImageList(context.Background(), types.ImageListOptions{
   169  		All:     true,
   170  		Filters: filter,
   171  	})
   172  	assert.NilError(t, err, "failed to list images")
   173  
   174  	return len(imageList) > 0
   175  }
   176  
   177  // EnsureFrozenImagesLinux loads frozen test images into the daemon
   178  // if they aren't already loaded
   179  func EnsureFrozenImagesLinux(testEnv *Execution) error {
   180  	if testEnv.OSType == "linux" {
   181  		err := load.FrozenImagesLinux(testEnv.APIClient(), frozenImages...)
   182  		if err != nil {
   183  			return errors.Wrap(err, "error loading frozen images")
   184  		}
   185  	}
   186  	return nil
   187  }