コード例 #1
0
ファイル: main.go プロジェクト: rlugojr/wercker
// Exit with either an error or a panic
func (s *SoftExit) Exit(v ...interface{}) error {
	if s.options.Debug {
		// Clearly this will cause it's own exit if it gets called.
		util.RootLogger().Panicln(v...)
	}
	util.RootLogger().Errorln(v...)
	return fmt.Errorf("Exiting.")
}
コード例 #2
0
ファイル: update.go プロジェクト: wercker/wercker
func getServerVersion(channel string) (*util.Versions, error) {
	logger := util.RootLogger().WithField("Logger", "getServerVersion")

	url := fmt.Sprintf("https://s3.amazonaws.com/downloads.wercker.com/cli/%s/version.json", channel)

	nv := &util.Versions{}
	client := &http.Client{}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		logger.WithField("Error", err).Debug("Unable to create request to version endpoint")
		return nil, err
	}

	res, err := client.Do(req)
	if err != nil {
		logger.WithField("Error", err).Debug("Unable to execute HTTP request to version endpoint")
		return nil, err
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		logger.WithField("Error", err).Debug("Unable to read response body")
		return nil, err
	}

	err = json.Unmarshal(body, nv)
	if err != nil {
		logger.WithField("Error", err).Debug("Unable to unmarshal versions")
		return nil, err
	}
	return nv, nil
}
コード例 #3
0
ファイル: main.go プロジェクト: rlugojr/wercker
// TODO(mies): maybe move to util.go at some point
func getYml(detected string, options *core.DetectOptions) {
	logger := util.RootLogger().WithField("Logger", "Main")

	yml := "wercker.yml"
	if _, err := os.Stat(yml); err == nil {
		logger.Println(yml, "already exists. Do you want to overwrite? (yes/no)")
		if !askForConfirmation() {
			logger.Println("Exiting...")
			os.Exit(1)
		}
	}
	url := fmt.Sprintf("%s/api/v2/yml/%s", options.BaseURL, detected)
	res, err := http.Get(url)
	if err != nil {
		logger.WithField("Error", err).Error("Unable to reach wercker API")
		os.Exit(1)
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		logger.WithField("Error", err).Error("Unable to read response")
	}

	err = ioutil.WriteFile("wercker.yml", body, 0644)
	if err != nil {
		logger.WithField("Error", err).Error("Unable to write wercker.yml file")
	}

}
コード例 #4
0
ファイル: step.go プロジェクト: rlugojr/wercker
func NewStep(config *core.StepConfig, options *core.PipelineOptions, dockerOptions *DockerOptions) (core.Step, error) {
	// NOTE(termie) Special case steps are special
	if config.ID == "internal/docker-push" {
		return NewDockerPushStep(config, options, dockerOptions)
	}
	if config.ID == "internal/docker-scratch-push" {
		return NewDockerScratchPushStep(config, options, dockerOptions)
	}
	if config.ID == "internal/store-container" {
		return NewStoreContainerStep(config, options, dockerOptions)
	}
	if strings.HasPrefix(config.ID, "internal/") {
		if !options.EnableDevSteps {
			util.RootLogger().Warnln("Ignoring dev step:", config.ID)
			return nil, nil
		}
	}
	if options.EnableDevSteps {
		if config.ID == "internal/watch" {
			return NewWatchStep(config, options, dockerOptions)
		}
		if config.ID == "internal/shell" {
			return NewShellStep(config, options, dockerOptions)
		}
	}
	return NewDockerStep(config, options, dockerOptions)
}
コード例 #5
0
ファイル: main.go プロジェクト: rlugojr/wercker
// DumpOptions prints out a sorted list of options
func DumpOptions(options interface{}, indent ...string) {
	indent = append(indent, "  ")
	s := reflect.ValueOf(options).Elem()
	typeOfT := s.Type()
	names := []string{}
	for i := 0; i < s.NumField(); i++ {
		// f := s.Field(i)
		fieldName := typeOfT.Field(i).Name
		if fieldName != "HostEnv" {
			names = append(names, fieldName)
		}
	}
	sort.Strings(names)
	logger := util.RootLogger().WithField("Logger", "Options")

	for _, name := range names {
		r := reflect.ValueOf(options)
		f := reflect.Indirect(r).FieldByName(name)
		if strings.HasSuffix(name, "Options") {
			if len(indent) > 1 && name == "GlobalOptions" {
				continue
			}
			logger.Debugln(fmt.Sprintf("%s%s %s", strings.Join(indent, ""), name, f.Type()))
			DumpOptions(f.Interface(), indent...)
		} else {
			logger.Debugln(fmt.Sprintf("%s%s %s = %v", strings.Join(indent, ""), name, f.Type(), f.Interface()))
		}
	}
}
コード例 #6
0
ファイル: options.go プロジェクト: wercker/wercker
// NewDeployOptions constructor
func NewDeployOptions(c util.Settings, e *util.Environment) (*PipelineOptions, error) {
	pipelineOpts, err := NewPipelineOptions(c, e)
	if err != nil {
		return nil, err
	}
	// default to last build output if none defined
	target, _ := c.String("target")
	if target == "" {
		found, err := util.Exists("./.wercker/latest/output")
		if err == nil && found {
			util.RootLogger().Println("No target specified, using recent build output.")
			pipelineOpts.ProjectPath, _ = filepath.Abs("./.wercker/latest/output")
		}
	}

	// if the deploy target path does not have a wercker.yml, use the current one
	werckerYml, _ := c.String("wercker-yml")
	if werckerYml == "" {
		found, _ := util.Exists(filepath.Join(pipelineOpts.ProjectPath, "wercker.yml"))
		if !found {
			pipelineOpts.WerckerYml = "./wercker.yml"
		}
	}

	if pipelineOpts.RunID == "" {
		pipelineOpts.RunID = uuid.NewRandom().String()
	}
	return pipelineOpts, nil
}
コード例 #7
0
ファイル: docker.go プロジェクト: rlugojr/wercker
func normalizeRegistry(address string) string {
	logger := util.RootLogger().WithField("Logger", "Docker")
	if address == "" {
		logger.Debugln("No registry address provided, using https://registry.hub.docker.com")
		return "https://registry.hub.docker.com/v1/"
	}
	parsed, err := url.Parse(address)
	if err != nil {
		logger.Errorln("Registry address is invalid, this will probably fail:", address)
		return address
	}
	if parsed.Scheme != "https" {
		logger.Warnln("Registry address is expected to begin with 'https://', forcing it to use https")
		parsed.Scheme = "https"
		address = parsed.String()
	}
	if strings.HasSuffix(address, "/") {
		address = address[:len(address)-1]
	}

	parts := strings.Split(address, "/")
	possiblyAPIVersionStr := parts[len(parts)-1]

	// we only support v1, so...
	if possiblyAPIVersionStr == "v2" {
		logger.Warnln("Registry API v2 not supported, using v1")
		newParts := append(parts[:len(parts)-1], "v1")
		address = strings.Join(newParts, "/")
	} else if possiblyAPIVersionStr != "v1" {
		newParts := append(parts, "v1")
		address = strings.Join(newParts, "/")
	}
	return address + "/"
}
コード例 #8
0
ファイル: docker.go プロジェクト: rlugojr/wercker
// NewDockerPushStep is a special step for doing docker pushes
func NewDockerPushStep(stepConfig *core.StepConfig, options *core.PipelineOptions, dockerOptions *DockerOptions) (*DockerPushStep, error) {
	name := "docker-push"
	displayName := "docker push"
	if stepConfig.Name != "" {
		displayName = stepConfig.Name
	}

	// Add a random number to the name to prevent collisions on disk
	stepSafeID := fmt.Sprintf("%s-%s", name, uuid.NewRandom().String())

	baseStep := core.NewBaseStep(core.BaseStepOptions{
		DisplayName: displayName,
		Env:         &util.Environment{},
		ID:          name,
		Name:        name,
		Owner:       "wercker",
		SafeID:      stepSafeID,
		Version:     util.Version(),
	})

	return &DockerPushStep{
		BaseStep:      baseStep,
		data:          stepConfig.Data,
		logger:        util.RootLogger().WithField("Logger", "DockerPushStep"),
		options:       options,
		dockerOptions: dockerOptions,
	}, nil
}
コード例 #9
0
ファイル: docker.go プロジェクト: rlugojr/wercker
// NewDockerClient based on options and env
func NewDockerClient(options *DockerOptions) (*DockerClient, error) {
	dockerHost := options.DockerHost
	tlsVerify := options.DockerTLSVerify

	logger := util.RootLogger().WithField("Logger", "Docker")

	var (
		client *docker.Client
		err    error
	)

	if tlsVerify == "1" {
		// We're using TLS, let's locate our certs and such
		// boot2docker puts its certs at...
		dockerCertPath := options.DockerCertPath

		// TODO(termie): maybe fast-fail if these don't exist?
		cert := path.Join(dockerCertPath, fmt.Sprintf("cert.pem"))
		ca := path.Join(dockerCertPath, fmt.Sprintf("ca.pem"))
		key := path.Join(dockerCertPath, fmt.Sprintf("key.pem"))
		client, err = docker.NewVersionnedTLSClient(dockerHost, cert, key, ca, "")
		if err != nil {
			return nil, err
		}
	} else {
		client, err = docker.NewClient(dockerHost)
		if err != nil {
			return nil, err
		}
	}
	return &DockerClient{Client: client, logger: logger}, nil
}
コード例 #10
0
ファイル: artifact.go プロジェクト: hughker/wercker
// NewDockerFileCollector constructor
func NewDockerFileCollector(client *DockerClient, containerID string) *DockerFileCollector {
	return &DockerFileCollector{
		client:      client,
		containerID: containerID,
		logger:      util.RootLogger().WithField("Logger", "DockerFileCollector"),
	}
}
コード例 #11
0
ファイル: box.go プロジェクト: umcodemonkey/wercker
// NewDockerBox from a name and other references
func NewDockerBox(boxConfig *core.BoxConfig, options *core.PipelineOptions, dockerOptions *DockerOptions) (*DockerBox, error) {
	name := boxConfig.ID

	if strings.Contains(name, "@") {
		return nil, fmt.Errorf("Invalid box name, '@' is not allowed in docker repositories.")
	}

	parts := strings.Split(name, ":")
	repository := parts[0]
	tag := "latest"
	if len(parts) > 1 {
		tag = parts[1]
	}
	if boxConfig.Tag != "" {
		tag = boxConfig.Tag
	}
	name = fmt.Sprintf("%s:%s", repository, tag)

	repoParts := strings.Split(repository, "/")
	shortName := repository
	if len(repoParts) > 1 {
		shortName = repoParts[len(repoParts)-1]
	}

	networkDisabled := false

	cmd := boxConfig.Cmd
	if cmd == "" {
		cmd = "/bin/bash"
	}

	entrypoint := boxConfig.Entrypoint

	logger := util.RootLogger().WithFields(util.LogFields{
		"Logger":    "Box",
		"Name":      name,
		"ShortName": shortName,
	})

	client, err := NewDockerClient(dockerOptions)
	if err != nil {
		return nil, err
	}
	return &DockerBox{
		Name:            name,
		ShortName:       shortName,
		client:          client,
		config:          boxConfig,
		options:         options,
		dockerOptions:   dockerOptions,
		repository:      repository,
		tag:             tag,
		networkDisabled: networkDisabled,
		logger:          logger,
		cmd:             cmd,
		entrypoint:      entrypoint,
		volumes:         []string{},
	}, nil
}
コード例 #12
0
ファイル: session.go プロジェクト: wercker/wercker
// NewDockerTransport constructor
func NewDockerTransport(options *core.PipelineOptions, dockerOptions *DockerOptions, containerID string) (core.Transport, error) {
	client, err := NewDockerClient(dockerOptions)
	if err != nil {
		return nil, err
	}
	logger := util.RootLogger().WithField("Logger", "DockerTransport")
	return &DockerTransport{options: options, client: client, containerID: containerID, logger: logger}, nil
}
コード例 #13
0
ファイル: service.go プロジェクト: hughker/wercker
// NewExternalServiceBox gives us an ExternalServiceBox from config
func NewExternalServiceBox(boxConfig *core.BoxConfig, options *core.PipelineOptions, dockerOptions *DockerOptions, builder Builder) (*ExternalServiceBox, error) {
	logger := util.RootLogger().WithField("Logger", "ExternalService")
	box := &DockerBox{options: options, dockerOptions: dockerOptions}
	return &ExternalServiceBox{
		InternalServiceBox: &InternalServiceBox{DockerBox: box, logger: logger},
		externalConfig:     boxConfig,
		builder:            builder,
	}, nil
}
コード例 #14
0
ファイル: session.go プロジェクト: wercker/wercker
// NewSession returns a new interactive session to a container.
func NewSession(options *PipelineOptions, transport Transport) *Session {
	logger := util.RootLogger().WithField("Logger", "Session")
	return &Session{
		options:    options,
		transport:  transport,
		logsHidden: false,
		logger:     logger,
	}
}
コード例 #15
0
ファイル: update.go プロジェクト: wercker/wercker
// AskForUpdate asks users if they want to update and returns the answer
func AskForUpdate() bool {
	fmt.Println("Would you like update? [yN]")
	reader := bufio.NewReader(os.Stdin)
	line, err := reader.ReadString('\n')
	if err != nil {
		util.RootLogger().Errorln("Problem reading answer", err)
		return false
	}
	return strings.HasPrefix(strings.ToLower(line), "y")
}
コード例 #16
0
ファイル: artifact.go プロジェクト: hughker/wercker
// NewArtificer returns an Artificer
func NewArtificer(options *core.PipelineOptions, dockerOptions *DockerOptions) *Artificer {
	logger := util.RootLogger().WithField("Logger", "Artificer")

	s3store := core.NewS3Store(options.AWSOptions)

	return &Artificer{
		options: options,
		logger:  logger,
		store:   s3store,
	}
}
コード例 #17
0
ファイル: api.go プロジェクト: wercker/wercker
// NewAPIClient returns our dumb client
func NewAPIClient(options *APIOptions) *APIClient {
	logger := util.RootLogger().WithFields(util.LogFields{
		"Logger": "API",
	})
	return &APIClient{
		baseURL: options.BaseURL,
		client:  &http.Client{},
		options: options,
		logger:  logger,
	}
}
コード例 #18
0
ファイル: main.go プロジェクト: rlugojr/wercker
func cmdLogout(options *core.LogoutOptions) error {
	soft := NewSoftExit(options.GlobalOptions)
	logger := util.RootLogger().WithField("Logger", "Main")

	logger.Println("Logging out")

	err := removeToken(options.GlobalOptions.AuthTokenStore)
	if err != nil {
		return soft.Exit(err)
	}
	return nil
}
コード例 #19
0
ファイル: update.go プロジェクト: wercker/wercker
// NewUpdater constructor
func NewUpdater(channel string) (*Updater, error) {
	serverVersion, err := getServerVersion(channel)
	if err != nil {
		return nil, err
	}
	return &Updater{
		CurrentVersion: util.GetVersions(),
		ServerVersion:  serverVersion,
		channel:        channel,
		l:              util.RootLogger().WithField("Logger", "Updater"),
	}, nil
}
コード例 #20
0
ファイル: runner.go プロジェクト: sgoings/wercker
// NewRunner from global options
func NewRunner(ctx context.Context, options *core.PipelineOptions, dockerOptions *dockerlocal.DockerOptions, getPipeline pipelineGetter) (*Runner, error) {
	e, err := core.EmitterFromContext(ctx)
	if err != nil {
		return nil, err
	}
	logger := util.RootLogger().WithField("Logger", "Runner")
	// h, err := NewLogHandler()
	// if err != nil {
	//   p.logger.WithField("Error", err).Panic("Unable to LogHandler")
	// }
	// h.ListenTo(e)

	if options.Debug {
		dh := core.NewDebugHandler()
		dh.ListenTo(e)
	}

	l, err := event.NewLiteralLogHandler(options)
	if err != nil {
		logger.WithField("Error", err).Panic("Unable to event.LiteralLogHandler")
	}
	l.ListenTo(e)

	var mh *event.MetricsEventHandler
	if options.ShouldKeenMetrics {
		mh, err = event.NewMetricsHandler(options)
		if err != nil {
			logger.WithField("Error", err).Panic("Unable to MetricsHandler")
		}
		mh.ListenTo(e)
	}

	var r *event.ReportHandler
	if options.ShouldReport {
		r, err := event.NewReportHandler(options.ReporterHost, options.ReporterKey)
		if err != nil {
			logger.WithField("Error", err).Panic("Unable to event.ReportHandler")
		}
		r.ListenTo(e)
	}

	return &Runner{
		options:       options,
		dockerOptions: dockerOptions,
		literalLogger: l,
		metrics:       mh,
		reporter:      r,
		getPipeline:   getPipeline,
		logger:        logger,
		emitter:       e,
		formatter:     &util.Formatter{options.GlobalOptions.ShowColors},
	}, nil
}
コード例 #21
0
ファイル: metricshandler.go プロジェクト: hughker/wercker
func getCollection(options *core.PipelineOptions) string {
	if options.BuildID != "" {
		return "build-events"
	}

	if options.DeployID != "" {
		return "deploy-events"
	}

	util.RootLogger().WithField("Logger", "Metrics").Panic("Metrics is only able to send metrics for builds or deploys")
	return ""
}
コード例 #22
0
ファイル: session_test.go プロジェクト: wercker/wercker
func (t *FakeTransport) Attach(sessionCtx context.Context, stdin io.Reader, stdout, stderr io.Writer) (context.Context, error) {
	fakeContext, cancel := context.WithCancel(sessionCtx)
	t.cancelFunc = cancel
	t.stdin = stdin
	t.stdout = stdout
	t.stderr = stderr

	t.inchan = make(chan string)
	t.outchan = make(chan string)

	go func() {
		for {
			var p []byte
			p = make([]byte, 1024)
			i, err := t.stdin.Read(p)
			s := string(p[:i])
			util.RootLogger().Println(fmt.Sprintf("(test)  stdin: %q", s))
			t.inchan <- s
			if err != nil {
				close(t.inchan)
				return
			}
		}
	}()

	go func() {
		for {
			s := <-t.outchan
			util.RootLogger().Println(fmt.Sprintf("(test) stdout: %q", s))
			_, err := t.stdout.Write([]byte(s))
			if err != nil {
				close(t.outchan)
				return
			}
		}
	}()

	return fakeContext, nil
}
コード例 #23
0
ファイル: literalloghandler.go プロジェクト: wercker/wercker
// NewLiteralLogHandler will create a new LiteralLogHandler.
func NewLiteralLogHandler(options *core.PipelineOptions) (*LiteralLogHandler, error) {
	var logger *util.Logger

	if options.Debug {
		logger = util.RootLogger()
	} else {
		logger = util.NewLogger()
		logger.Formatter = &reporter.LiteralFormatter{}
		logger.Level = log.InfoLevel
	}

	return &LiteralLogHandler{l: logger, options: options}, nil
}
コード例 #24
0
ファイル: main.go プロジェクト: rlugojr/wercker
// detectProject inspects the the current directory that wercker is running in
// and detects the project's programming language
func cmdDetect(options *core.DetectOptions) error {
	soft := NewSoftExit(options.GlobalOptions)
	logger := util.RootLogger().WithField("Logger", "Main")

	logger.Println("########### Detecting your project! #############")

	detected := ""

	d, err := os.Open(".")
	if err != nil {
		logger.WithField("Error", err).Error("Unable to open directory")
		soft.Exit(err)
	}
	defer d.Close()

	files, err := d.Readdir(-1)
	if err != nil {
		logger.WithField("Error", err).Error("Unable to read directory")
		soft.Exit(err)
	}
outer:
	for _, f := range files {
		switch {
		case f.Name() == "package.json":
			detected = "nodejs"
			break outer

		case f.Name() == "requirements.txt":
			detected = "python"
			break outer

		case f.Name() == "Gemfile":
			detected = "ruby"
			break outer

		case filepath.Ext(f.Name()) == ".go":
			detected = "golang"
			break outer
		}
	}
	if detected == "" {
		logger.Println("No stack detected, generating default wercker.yml")
		detected = "default"
	} else {
		logger.Println("Detected:", detected)
		logger.Println("Generating wercker.yml")
	}
	getYml(detected, options)
	return nil
}
コード例 #25
0
ファイル: s3store.go プロジェクト: hughker/wercker
// NewS3Store creates a new S3Store
func NewS3Store(options *AWSOptions) *S3Store {
	logger := util.RootLogger().WithField("Logger", "S3Store")
	if options == nil {
		logger.Panic("options cannot be nil")
	}

	client := s3.New(&aws.Config{Region: &options.AWSRegion})

	return &S3Store{
		client:  client,
		logger:  logger,
		options: options,
	}
}
コード例 #26
0
ファイル: reporthandler.go プロジェクト: hughker/wercker
// NewReportHandler will create a new ReportHandler.
func NewReportHandler(werckerHost, token string) (*ReportHandler, error) {
	r, err := reporter.New(werckerHost, token)
	if err != nil {
		return nil, err
	}

	writers := make(map[string]*reporter.LogWriter)
	logger := util.RootLogger().WithField("Logger", "Reporter")
	h := &ReportHandler{
		reporter: r,
		writers:  writers,
		logger:   logger,
	}
	return h, nil
}
コード例 #27
0
ファイル: artifact.go プロジェクト: wercker/wercker
// NewArtificer returns an Artificer
func NewArtificer(options *core.PipelineOptions, dockerOptions *DockerOptions) *Artificer {
	logger := util.RootLogger().WithField("Logger", "Artificer")

	var store core.Store
	if options.ShouldStoreS3 {
		store = core.NewS3Store(options.AWSOptions)
	}

	return &Artificer{
		options:       options,
		dockerOptions: dockerOptions,
		logger:        logger,
		store:         store,
	}
}
コード例 #28
0
ファイル: main.go プロジェクト: rlugojr/wercker
// Retrieving user input utility functions
func askForConfirmation() bool {
	var response string
	_, err := fmt.Scanln(&response)
	if err != nil {
		util.RootLogger().WithField("Logger", "Util").Fatal(err)
	}
	response = strings.ToLower(response)
	if strings.HasPrefix(response, "y") {
		return true
	} else if strings.HasPrefix(response, "n") {
		return false
	} else {
		println("Please type yes or no and then press enter:")
		return askForConfirmation()
	}
}
コード例 #29
0
ファイル: options.go プロジェクト: umcodemonkey/wercker
// guessAuthToken will attempt to read from the token store location if
// no auth token was provided
func guessAuthToken(c util.Settings, e *util.Environment, authTokenStore string) string {
	token, _ := c.GlobalString("auth-token")
	if token != "" {
		return token
	}
	if foundToken, _ := util.Exists(authTokenStore); !foundToken {
		return ""
	}

	tokenBytes, err := ioutil.ReadFile(authTokenStore)
	if err != nil {
		util.RootLogger().WithField("Logger", "Options").Errorln(err)
		return ""
	}
	return strings.TrimSpace(string(tokenBytes))
}
コード例 #30
0
ファイル: docker.go プロジェクト: rlugojr/wercker
// CheckAccess checks whether a user can read or write an image
// TODO(termie): this really uses the docker registry code rather than the
//               client so, maybe this is the wrong place
func (c *DockerClient) CheckAccess(opts CheckAccessOptions) (bool, error) {
	logger := util.RootLogger().WithField("Logger", "Docker")
	logger.Debug("Checking access for ", opts.Repository)

	// Do the steps described here: https://gist.github.com/termie/bc0334b086697a162f67
	name := normalizeRepo(opts.Repository)
	logger.Debug("Normalized repo ", name)

	auth := registry.BasicAuth{
		Username: opts.Auth.Username,
		Password: opts.Auth.Password,
	}
	client := registry.NewClient()

	reg := normalizeRegistry(opts.Registry)
	logger.Debug("Normalized Registry ", reg)

	client.BaseURL, _ = url.Parse(reg)

	if opts.Access == "write" {
		if _, err := client.Hub.GetWriteToken(name, auth); err != nil {
			if err.Error() == "Server returned status 401" || err.Error() == "Server returned status 403" {
				return false, nil
			}
			return false, err
		}
	} else if opts.Access == "read" {
		if opts.Auth.Username != "" {
			if _, err := client.Hub.GetReadTokenWithAuth(name, auth); err != nil {
				if err.Error() == "Server returned status 401" || err.Error() == "Server returned status 403" {
					return false, nil
				}
				return false, err
			}
		} else {
			if _, err := client.Hub.GetReadToken(name); err != nil {
				if err.Error() == "Server returned status 401" || err.Error() == "Server returned status 403" {
					return false, nil
				}
				return false, err
			}
		}
	} else {
		return false, fmt.Errorf("Invalid access type requested: %s", opts.Access)
	}
	return true, nil
}