Merge pull request #1415 from dhiltgen/fix_panic_master

Fix panic in display only case for license - forward port #1408 to master
This commit is contained in:
Sebastiaan van Stijn 2018-11-15 00:55:48 +01:00 committed by GitHub
commit 29625f6124
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 106 additions and 23 deletions

View File

@ -16,19 +16,21 @@ import (
) )
type activateOptions struct { type activateOptions struct {
licenseFile string licenseFile string
version string version string
registryPrefix string registryPrefix string
format string format string
image string image string
quiet bool quiet bool
displayOnly bool displayOnly bool
sockPath string sockPath string
licenseLoginFunc func(ctx context.Context, authConfig *types.AuthConfig) (licenseutils.HubUser, error)
} }
// newActivateCommand creates a new `docker engine activate` command // newActivateCommand creates a new `docker engine activate` command
func newActivateCommand(dockerCli command.Cli) *cobra.Command { func newActivateCommand(dockerCli command.Cli) *cobra.Command {
var options activateOptions var options activateOptions
options.licenseLoginFunc = licenseutils.Login
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "activate [OPTIONS]", Use: "activate [OPTIONS]",
@ -60,7 +62,7 @@ https://hub.docker.com/ then specify the file with the '--license' flag.
flags.StringVar(&options.registryPrefix, "registry-prefix", clitypes.RegistryPrefix, "Override the default location where engine images are pulled") flags.StringVar(&options.registryPrefix, "registry-prefix", clitypes.RegistryPrefix, "Override the default location where engine images are pulled")
flags.StringVar(&options.image, "engine-image", "", "Specify engine image") flags.StringVar(&options.image, "engine-image", "", "Specify engine image")
flags.StringVar(&options.format, "format", "", "Pretty-print licenses using a Go template") flags.StringVar(&options.format, "format", "", "Pretty-print licenses using a Go template")
flags.BoolVar(&options.displayOnly, "display-only", false, "only display the available licenses and exit") flags.BoolVar(&options.displayOnly, "display-only", false, "only display license information and exit")
flags.BoolVar(&options.quiet, "quiet", false, "Only display available licenses by ID") flags.BoolVar(&options.quiet, "quiet", false, "Only display available licenses by ID")
flags.StringVar(&options.sockPath, "containerd", "", "override default location of containerd endpoint") flags.StringVar(&options.sockPath, "containerd", "", "override default location of containerd endpoint")
@ -90,6 +92,9 @@ func runActivate(cli command.Cli, options activateOptions) error {
if license, err = getLicenses(ctx, authConfig, cli, options); err != nil { if license, err = getLicenses(ctx, authConfig, cli, options); err != nil {
return err return err
} }
if options.displayOnly {
return nil
}
} else { } else {
if license, err = licenseutils.LoadLocalIssuedLicense(ctx, options.licenseFile); err != nil { if license, err = licenseutils.LoadLocalIssuedLicense(ctx, options.licenseFile); err != nil {
return err return err
@ -136,7 +141,7 @@ Restart docker with 'systemctl restart docker' to complete the activation.`)
} }
func getLicenses(ctx context.Context, authConfig *types.AuthConfig, cli command.Cli, options activateOptions) (*model.IssuedLicense, error) { func getLicenses(ctx context.Context, authConfig *types.AuthConfig, cli command.Cli, options activateOptions) (*model.IssuedLicense, error) {
user, err := licenseutils.Login(ctx, authConfig) user, err := options.licenseLoginFunc(ctx, authConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,14 +1,19 @@
package engine package engine
import ( import (
"context"
"fmt" "fmt"
"os" "os"
"testing" "testing"
"time"
"github.com/docker/cli/internal/licenseutils"
"github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test"
clitypes "github.com/docker/cli/types" clitypes "github.com/docker/cli/types"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/client" "github.com/docker/docker/client"
"github.com/docker/licensing"
"github.com/docker/licensing/model"
"gotest.tools/assert" "gotest.tools/assert"
"gotest.tools/fs" "gotest.tools/fs"
"gotest.tools/golden" "gotest.tools/golden"
@ -71,3 +76,73 @@ func TestActivateExpiredLicenseDryRun(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
golden.Assert(t, c.OutBuffer().String(), "expired-license-display-only.golden") golden.Assert(t, c.OutBuffer().String(), "expired-license-display-only.golden")
} }
type mockLicenseClient struct{}
func (c mockLicenseClient) LoginViaAuth(ctx context.Context, username, password string) (authToken string, err error) {
return "", fmt.Errorf("not implemented")
}
func (c mockLicenseClient) GetHubUserOrgs(ctx context.Context, authToken string) (orgs []model.Org, err error) {
return nil, fmt.Errorf("not implemented")
}
func (c mockLicenseClient) GetHubUserByName(ctx context.Context, username string) (user *model.User, err error) {
return nil, fmt.Errorf("not implemented")
}
func (c mockLicenseClient) VerifyLicense(ctx context.Context, license model.IssuedLicense) (res *model.CheckResponse, err error) {
return nil, fmt.Errorf("not implemented")
}
func (c mockLicenseClient) GenerateNewTrialSubscription(ctx context.Context, authToken, dockerID, email string) (subscriptionID string, err error) {
return "", fmt.Errorf("not implemented")
}
func (c mockLicenseClient) ListSubscriptions(ctx context.Context, authToken, dockerID string) (response []*model.Subscription, err error) {
expires := time.Date(2010, time.January, 1, 0, 0, 0, 0, time.UTC)
return []*model.Subscription{
{
State: "active",
Expires: &expires,
},
}, nil
}
func (c mockLicenseClient) ListSubscriptionsDetails(ctx context.Context, authToken, dockerID string) (response []*model.SubscriptionDetail, err error) {
return nil, fmt.Errorf("not implemented")
}
func (c mockLicenseClient) DownloadLicenseFromHub(ctx context.Context, authToken, subscriptionID string) (license *model.IssuedLicense, err error) {
return nil, fmt.Errorf("not implemented")
}
func (c mockLicenseClient) ParseLicense(license []byte) (parsedLicense *model.IssuedLicense, err error) {
return nil, fmt.Errorf("not implemented")
}
func (c mockLicenseClient) StoreLicense(ctx context.Context, dclnt licensing.WrappedDockerClient, licenses *model.IssuedLicense, localRootDir string) error {
return fmt.Errorf("not implemented")
}
func (c mockLicenseClient) LoadLocalLicense(ctx context.Context, dclnt licensing.WrappedDockerClient) (*model.Subscription, error) {
return nil, fmt.Errorf("not implemented")
}
func (c mockLicenseClient) SummarizeLicense(res *model.CheckResponse, keyID string) *model.Subscription {
return nil
}
func TestActivateDisplayOnlyHub(t *testing.T) {
isRoot = func() bool { return true }
c := test.NewFakeCli(&verClient{client.Client{}, types.Version{}, nil, types.Info{}, nil})
c.SetContainerizedEngineClient(
func(string) (clitypes.ContainerizedClient, error) {
return &fakeContainerizedEngineClient{}, nil
},
)
hubUser := licenseutils.HubUser{
Client: mockLicenseClient{},
}
options := activateOptions{
licenseLoginFunc: func(ctx context.Context, authConfig *types.AuthConfig) (licenseutils.HubUser, error) {
return hubUser, nil
},
displayOnly: true,
}
c.OutBuffer().Reset()
err := runActivate(c, options)
assert.NilError(t, err)
golden.Assert(t, c.OutBuffer().String(), "expired-hub-license-display-only.golden")
}

View File

@ -0,0 +1,3 @@
Looking for existing licenses for ...
NUM OWNER PRODUCT ID EXPIRES PRICING COMPONENTS
0 2010-01-01 00:00:00 +0000 UTC

View File

@ -20,7 +20,7 @@ import (
// HubUser wraps a licensing client and holds key information // HubUser wraps a licensing client and holds key information
// for a user to avoid multiple lookups // for a user to avoid multiple lookups
type HubUser struct { type HubUser struct {
client licensing.Client Client licensing.Client
token string token string
User model.User User model.User
Orgs []model.Org Orgs []model.Org
@ -73,7 +73,7 @@ func Login(ctx context.Context, authConfig *types.AuthConfig) (HubUser, error) {
return HubUser{}, err return HubUser{}, err
} }
return HubUser{ return HubUser{
client: lclient, Client: lclient,
token: token, token: token,
User: *user, User: *user,
Orgs: orgs, Orgs: orgs,
@ -83,12 +83,12 @@ func Login(ctx context.Context, authConfig *types.AuthConfig) (HubUser, error) {
// GetAvailableLicenses finds all available licenses for a given account and their orgs // GetAvailableLicenses finds all available licenses for a given account and their orgs
func (u HubUser) GetAvailableLicenses(ctx context.Context) ([]LicenseDisplay, error) { func (u HubUser) GetAvailableLicenses(ctx context.Context) ([]LicenseDisplay, error) {
subs, err := u.client.ListSubscriptions(ctx, u.token, u.User.ID) subs, err := u.Client.ListSubscriptions(ctx, u.token, u.User.ID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, org := range u.Orgs { for _, org := range u.Orgs {
orgSub, err := u.client.ListSubscriptions(ctx, u.token, org.ID) orgSub, err := u.Client.ListSubscriptions(ctx, u.token, org.ID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -134,16 +134,16 @@ func (u HubUser) GetAvailableLicenses(ctx context.Context) ([]LicenseDisplay, er
// GenerateTrialLicense will generate a new trial license for the specified user or org // GenerateTrialLicense will generate a new trial license for the specified user or org
func (u HubUser) GenerateTrialLicense(ctx context.Context, targetID string) (*model.IssuedLicense, error) { func (u HubUser) GenerateTrialLicense(ctx context.Context, targetID string) (*model.IssuedLicense, error) {
subID, err := u.client.GenerateNewTrialSubscription(ctx, u.token, targetID, u.User.Email) subID, err := u.Client.GenerateNewTrialSubscription(ctx, u.token, targetID, u.User.Email)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return u.client.DownloadLicenseFromHub(ctx, u.token, subID) return u.Client.DownloadLicenseFromHub(ctx, u.token, subID)
} }
// GetIssuedLicense will download a license by ID // GetIssuedLicense will download a license by ID
func (u HubUser) GetIssuedLicense(ctx context.Context, ID string) (*model.IssuedLicense, error) { func (u HubUser) GetIssuedLicense(ctx context.Context, ID string) (*model.IssuedLicense, error) {
return u.client.DownloadLicenseFromHub(ctx, u.token, ID) return u.Client.DownloadLicenseFromHub(ctx, u.token, ID)
} }
// LoadLocalIssuedLicense will load a local license file // LoadLocalIssuedLicense will load a local license file

View File

@ -43,7 +43,7 @@ func TestGetOrgByID(t *testing.T) {
func TestGetAvailableLicensesListFail(t *testing.T) { func TestGetAvailableLicensesListFail(t *testing.T) {
ctx := context.Background() ctx := context.Background()
user := HubUser{ user := HubUser{
client: &fakeLicensingClient{ Client: &fakeLicensingClient{
listSubscriptionsFunc: func(ctx context.Context, authToken, dockerID string) (response []*model.Subscription, err error) { listSubscriptionsFunc: func(ctx context.Context, authToken, dockerID string) (response []*model.Subscription, err error) {
return nil, fmt.Errorf("list subscriptions error") return nil, fmt.Errorf("list subscriptions error")
}, },
@ -59,7 +59,7 @@ func TestGetAvailableLicensesOrgFail(t *testing.T) {
Orgs: []model.Org{ Orgs: []model.Org{
{ID: "orgid"}, {ID: "orgid"},
}, },
client: &fakeLicensingClient{ Client: &fakeLicensingClient{
listSubscriptionsFunc: func(ctx context.Context, authToken, dockerID string) (response []*model.Subscription, err error) { listSubscriptionsFunc: func(ctx context.Context, authToken, dockerID string) (response []*model.Subscription, err error) {
if dockerID == "orgid" { if dockerID == "orgid" {
return nil, fmt.Errorf("list subscriptions org error") return nil, fmt.Errorf("list subscriptions org error")
@ -86,7 +86,7 @@ func TestGetAvailableLicensesHappy(t *testing.T) {
Orgname: "orgname", Orgname: "orgname",
}, },
}, },
client: &fakeLicensingClient{ Client: &fakeLicensingClient{
listSubscriptionsFunc: func(ctx context.Context, authToken, dockerID string) (response []*model.Subscription, err error) { listSubscriptionsFunc: func(ctx context.Context, authToken, dockerID string) (response []*model.Subscription, err error) {
if dockerID == "orgid" { if dockerID == "orgid" {
return []*model.Subscription{ return []*model.Subscription{
@ -146,7 +146,7 @@ func TestGetAvailableLicensesHappy(t *testing.T) {
func TestGenerateTrialFail(t *testing.T) { func TestGenerateTrialFail(t *testing.T) {
ctx := context.Background() ctx := context.Background()
user := HubUser{ user := HubUser{
client: &fakeLicensingClient{ Client: &fakeLicensingClient{
generateNewTrialSubscriptionFunc: func(ctx context.Context, authToken, dockerID, email string) (subscriptionID string, err error) { generateNewTrialSubscriptionFunc: func(ctx context.Context, authToken, dockerID, email string) (subscriptionID string, err error) {
return "", fmt.Errorf("generate trial failure") return "", fmt.Errorf("generate trial failure")
}, },
@ -160,7 +160,7 @@ func TestGenerateTrialFail(t *testing.T) {
func TestGenerateTrialHappy(t *testing.T) { func TestGenerateTrialHappy(t *testing.T) {
ctx := context.Background() ctx := context.Background()
user := HubUser{ user := HubUser{
client: &fakeLicensingClient{ Client: &fakeLicensingClient{
generateNewTrialSubscriptionFunc: func(ctx context.Context, authToken, dockerID, email string) (subscriptionID string, err error) { generateNewTrialSubscriptionFunc: func(ctx context.Context, authToken, dockerID, email string) (subscriptionID string, err error) {
return "subid", nil return "subid", nil
}, },
@ -174,7 +174,7 @@ func TestGenerateTrialHappy(t *testing.T) {
func TestGetIssuedLicense(t *testing.T) { func TestGetIssuedLicense(t *testing.T) {
ctx := context.Background() ctx := context.Background()
user := HubUser{ user := HubUser{
client: &fakeLicensingClient{}, Client: &fakeLicensingClient{},
} }
id := "idgoeshere" id := "idgoeshere"
_, err := user.GetIssuedLicense(ctx, id) _, err := user.GetIssuedLicense(ctx, id)