github.com/itscaro/cli@v0.0.0-20190705081621-c9db0fe93829/cli/command/engine/activate.go (about)

     1  package engine
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/docker/cli/cli/command"
     9  	"github.com/docker/cli/cli/command/formatter"
    10  	"github.com/docker/cli/internal/licenseutils"
    11  	clitypes "github.com/docker/cli/types"
    12  	"github.com/docker/docker/api/types"
    13  	"github.com/docker/licensing/model"
    14  	"github.com/pkg/errors"
    15  	"github.com/spf13/cobra"
    16  )
    17  
    18  type activateOptions struct {
    19  	licenseFile      string
    20  	version          string
    21  	registryPrefix   string
    22  	format           string
    23  	image            string
    24  	quiet            bool
    25  	displayOnly      bool
    26  	sockPath         string
    27  	licenseLoginFunc func(ctx context.Context, authConfig *types.AuthConfig) (licenseutils.HubUser, error)
    28  }
    29  
    30  // newActivateCommand creates a new `docker engine activate` command
    31  func newActivateCommand(dockerCli command.Cli) *cobra.Command {
    32  	var options activateOptions
    33  	options.licenseLoginFunc = licenseutils.Login
    34  
    35  	cmd := &cobra.Command{
    36  		Use:   "activate [OPTIONS]",
    37  		Short: "Activate Enterprise Edition",
    38  		Long: `Activate Enterprise Edition.
    39  
    40  With this command you may apply an existing Docker enterprise license, or
    41  interactively download one from Docker. In the interactive exchange, you can
    42  sign up for a new trial, or download an existing license. If you are
    43  currently running a Community Edition engine, the daemon will be updated to
    44  the Enterprise Edition Docker engine with additional capabilities and long
    45  term support.
    46  
    47  For more information about different Docker Enterprise license types visit
    48  https://www.docker.com/licenses
    49  
    50  For non-interactive scriptable deployments, download your license from
    51  https://hub.docker.com/ then specify the file with the '--license' flag.
    52  `,
    53  		RunE: func(cmd *cobra.Command, args []string) error {
    54  			return runActivate(dockerCli, options)
    55  		},
    56  	}
    57  
    58  	flags := cmd.Flags()
    59  
    60  	flags.StringVar(&options.licenseFile, "license", "", "License File")
    61  	flags.StringVar(&options.version, "version", "", "Specify engine version (default is to use currently running version)")
    62  	flags.StringVar(&options.registryPrefix, "registry-prefix", clitypes.RegistryPrefix, "Override the default location where engine images are pulled")
    63  	flags.StringVar(&options.image, "engine-image", "", "Specify engine image")
    64  	flags.StringVar(&options.format, "format", "", "Pretty-print licenses using a Go template")
    65  	flags.BoolVar(&options.displayOnly, "display-only", false, "only display license information and exit")
    66  	flags.BoolVar(&options.quiet, "quiet", false, "Only display available licenses by ID")
    67  	flags.StringVar(&options.sockPath, "containerd", "", "override default location of containerd endpoint")
    68  
    69  	return cmd
    70  }
    71  
    72  func runActivate(cli command.Cli, options activateOptions) error {
    73  	if !isRoot() {
    74  		return errors.New("this command must be run as a privileged user")
    75  	}
    76  	ctx := context.Background()
    77  	client, err := cli.NewContainerizedEngineClient(options.sockPath)
    78  	if err != nil {
    79  		return errors.Wrap(err, "unable to access local containerd")
    80  	}
    81  	defer client.Close()
    82  
    83  	authConfig, err := getRegistryAuth(cli, options.registryPrefix)
    84  	if err != nil {
    85  		return err
    86  	}
    87  
    88  	var license *model.IssuedLicense
    89  
    90  	// Lookup on hub if no license provided via params
    91  	if options.licenseFile == "" {
    92  		if license, err = getLicenses(ctx, authConfig, cli, options); err != nil {
    93  			return err
    94  		}
    95  		if options.displayOnly {
    96  			return nil
    97  		}
    98  	} else {
    99  		if license, err = licenseutils.LoadLocalIssuedLicense(ctx, options.licenseFile); err != nil {
   100  			return err
   101  		}
   102  	}
   103  	summary, err := licenseutils.GetLicenseSummary(ctx, *license)
   104  	if err != nil {
   105  		return err
   106  	}
   107  	fmt.Fprintf(cli.Out(), "License: %s\n", summary)
   108  	if options.displayOnly {
   109  		return nil
   110  	}
   111  	dclient := cli.Client()
   112  	if err = licenseutils.ApplyLicense(ctx, dclient, license); err != nil {
   113  		return err
   114  	}
   115  
   116  	// Short circuit if the user didn't specify a version and we're already running enterprise
   117  	if options.version == "" {
   118  		serverVersion, err := dclient.ServerVersion(ctx)
   119  		if err != nil {
   120  			return err
   121  		}
   122  		if strings.Contains(strings.ToLower(serverVersion.Platform.Name), "enterprise") {
   123  			fmt.Fprintln(cli.Out(), "Successfully activated engine license on existing enterprise engine.")
   124  			return nil
   125  		}
   126  		options.version = serverVersion.Version
   127  	}
   128  
   129  	opts := clitypes.EngineInitOptions{
   130  		RegistryPrefix: options.registryPrefix,
   131  		EngineImage:    options.image,
   132  		EngineVersion:  options.version,
   133  	}
   134  
   135  	if err := client.ActivateEngine(ctx, opts, cli.Out(), authConfig); err != nil {
   136  		return err
   137  	}
   138  	fmt.Fprintln(cli.Out(), `Successfully activated engine.
   139  Restart docker with 'systemctl restart docker' to complete the activation.`)
   140  	return nil
   141  }
   142  
   143  func getLicenses(ctx context.Context, authConfig *types.AuthConfig, cli command.Cli, options activateOptions) (*model.IssuedLicense, error) {
   144  	user, err := options.licenseLoginFunc(ctx, authConfig)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	fmt.Fprintf(cli.Out(), "Looking for existing licenses for %s...\n", user.User.Username)
   149  	subs, err := user.GetAvailableLicenses(ctx)
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  	if len(subs) == 0 {
   154  		return doTrialFlow(ctx, cli, user)
   155  	}
   156  
   157  	format := options.format
   158  	if len(format) == 0 {
   159  		format = formatter.TableFormatKey
   160  	}
   161  
   162  	updatesCtx := formatter.Context{
   163  		Output: cli.Out(),
   164  		Format: NewSubscriptionsFormat(format, options.quiet),
   165  		Trunc:  false,
   166  	}
   167  	if err := SubscriptionsWrite(updatesCtx, subs); err != nil {
   168  		return nil, err
   169  	}
   170  	if options.displayOnly {
   171  		return nil, nil
   172  	}
   173  	fmt.Fprintf(cli.Out(), "Please pick a license by number: ")
   174  	var num int
   175  	if _, err := fmt.Fscan(cli.In(), &num); err != nil {
   176  		return nil, errors.Wrap(err, "failed to read user input")
   177  	}
   178  	if num < 0 || num >= len(subs) {
   179  		return nil, fmt.Errorf("invalid choice")
   180  	}
   181  	return user.GetIssuedLicense(ctx, subs[num].ID)
   182  }
   183  
   184  func doTrialFlow(ctx context.Context, cli command.Cli, user licenseutils.HubUser) (*model.IssuedLicense, error) {
   185  	if !command.PromptForConfirmation(cli.In(), cli.Out(),
   186  		"No existing licenses found, would you like to set up a new Enterprise Basic Trial license?") {
   187  		return nil, fmt.Errorf("you must have an existing enterprise license or generate a new trial to use the Enterprise Docker Engine")
   188  	}
   189  	targetID := user.User.ID
   190  	// If the user is a member of any organizations, allow trials generated against them
   191  	if len(user.Orgs) > 0 {
   192  		fmt.Fprintf(cli.Out(), "%d\t%s\n", 0, user.User.Username)
   193  		for i, org := range user.Orgs {
   194  			fmt.Fprintf(cli.Out(), "%d\t%s\n", i+1, org.Orgname)
   195  		}
   196  		fmt.Fprintf(cli.Out(), "Please choose an account to generate the trial in:")
   197  		var num int
   198  		if _, err := fmt.Fscan(cli.In(), &num); err != nil {
   199  			return nil, errors.Wrap(err, "failed to read user input")
   200  		}
   201  		if num < 0 || num > len(user.Orgs) {
   202  			return nil, fmt.Errorf("invalid choice")
   203  		}
   204  		if num > 0 {
   205  			targetID = user.Orgs[num-1].ID
   206  		}
   207  	}
   208  	return user.GenerateTrialLicense(ctx, targetID)
   209  }