github.com/AliyunContainerService/cli@v0.0.0-20181009023821-814ced4b30d0/internal/licenseutils/utils.go (about)

     1  package licenseutils
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"net/http"
    10  	"net/url"
    11  	"strings"
    12  
    13  	"github.com/docker/docker/api/types"
    14  	"github.com/docker/licensing"
    15  	"github.com/docker/licensing/model"
    16  	"github.com/pkg/errors"
    17  	"github.com/sirupsen/logrus"
    18  )
    19  
    20  // HubUser wraps a licensing client and holds key information
    21  // for a user to avoid multiple lookups
    22  type HubUser struct {
    23  	client licensing.Client
    24  	token  string
    25  	User   model.User
    26  	Orgs   []model.Org
    27  }
    28  
    29  //GetOrgByID finds the org by the ID in the users list of orgs
    30  func (u HubUser) GetOrgByID(orgID string) (model.Org, error) {
    31  	for _, org := range u.Orgs {
    32  		if org.ID == orgID {
    33  			return org, nil
    34  		}
    35  	}
    36  	return model.Org{}, fmt.Errorf("org %s not found", orgID)
    37  }
    38  
    39  func getClient() (licensing.Client, error) {
    40  	baseURI, err := url.Parse(licensingDefaultBaseURI)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  
    45  	return licensing.New(&licensing.Config{
    46  		BaseURI:    *baseURI,
    47  		HTTPClient: &http.Client{},
    48  		PublicKeys: licensingPublicKeys,
    49  	})
    50  }
    51  
    52  // Login to the license server and return a client that can be used to look up and download license files or generate new trial licenses
    53  func Login(ctx context.Context, authConfig *types.AuthConfig) (HubUser, error) {
    54  	lclient, err := getClient()
    55  	if err != nil {
    56  		return HubUser{}, err
    57  	}
    58  
    59  	// For licensing we know they must have a valid login session
    60  	if authConfig.Username == "" {
    61  		return HubUser{}, fmt.Errorf("you must be logged in to access licenses.  Please use 'docker login' then try again")
    62  	}
    63  	token, err := lclient.LoginViaAuth(ctx, authConfig.Username, authConfig.Password)
    64  	if err != nil {
    65  		return HubUser{}, err
    66  	}
    67  	user, err := lclient.GetHubUserByName(ctx, authConfig.Username)
    68  	if err != nil {
    69  		return HubUser{}, err
    70  	}
    71  	orgs, err := lclient.GetHubUserOrgs(ctx, token)
    72  	if err != nil {
    73  		return HubUser{}, err
    74  	}
    75  	return HubUser{
    76  		client: lclient,
    77  		token:  token,
    78  		User:   *user,
    79  		Orgs:   orgs,
    80  	}, nil
    81  
    82  }
    83  
    84  // GetAvailableLicenses finds all available licenses for a given account and their orgs
    85  func (u HubUser) GetAvailableLicenses(ctx context.Context) ([]LicenseDisplay, error) {
    86  	subs, err := u.client.ListSubscriptions(ctx, u.token, u.User.ID)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	for _, org := range u.Orgs {
    91  		orgSub, err := u.client.ListSubscriptions(ctx, u.token, org.ID)
    92  		if err != nil {
    93  			return nil, err
    94  		}
    95  		subs = append(subs, orgSub...)
    96  	}
    97  
    98  	// Convert the SubscriptionDetails to a more user-friendly type to render in the CLI
    99  
   100  	res := []LicenseDisplay{}
   101  
   102  	// Filter out expired licenses
   103  	i := 0
   104  	for _, s := range subs {
   105  		if s.State != "expired" && s.Expires != nil {
   106  			owner := ""
   107  			if s.DockerID == u.User.ID {
   108  				owner = u.User.Username
   109  			} else {
   110  				ownerOrg, err := u.GetOrgByID(s.DockerID)
   111  				if err == nil {
   112  					owner = ownerOrg.Orgname
   113  				} else {
   114  					owner = "unknown"
   115  					logrus.Debugf("Unable to lookup org ID %s: %s", s.DockerID, err)
   116  				}
   117  			}
   118  			comps := []string{}
   119  			for _, pc := range s.PricingComponents {
   120  				comps = append(comps, fmt.Sprintf("%s:%d", pc.Name, pc.Value))
   121  			}
   122  			res = append(res, LicenseDisplay{
   123  				Subscription:     *s,
   124  				Num:              i,
   125  				Owner:            owner,
   126  				ComponentsString: strings.Join(comps, ","),
   127  			})
   128  			i++
   129  		}
   130  	}
   131  
   132  	return res, nil
   133  }
   134  
   135  // GenerateTrialLicense will generate a new trial license for the specified user or org
   136  func (u HubUser) GenerateTrialLicense(ctx context.Context, targetID string) (*model.IssuedLicense, error) {
   137  	subID, err := u.client.GenerateNewTrialSubscription(ctx, u.token, targetID, u.User.Email)
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	return u.client.DownloadLicenseFromHub(ctx, u.token, subID)
   142  }
   143  
   144  // GetIssuedLicense will download a license by ID
   145  func (u HubUser) GetIssuedLicense(ctx context.Context, ID string) (*model.IssuedLicense, error) {
   146  	return u.client.DownloadLicenseFromHub(ctx, u.token, ID)
   147  }
   148  
   149  // LoadLocalIssuedLicense will load a local license file
   150  func LoadLocalIssuedLicense(ctx context.Context, filename string) (*model.IssuedLicense, error) {
   151  	lclient, err := getClient()
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  	return doLoadLocalIssuedLicense(ctx, filename, lclient)
   156  }
   157  
   158  // GetLicenseSummary summarizes the license for the user
   159  func GetLicenseSummary(ctx context.Context, license model.IssuedLicense) (string, error) {
   160  	lclient, err := getClient()
   161  	if err != nil {
   162  		return "", err
   163  	}
   164  
   165  	cr, err := lclient.VerifyLicense(ctx, license)
   166  	if err != nil {
   167  		return "", err
   168  	}
   169  	return lclient.SummarizeLicense(cr, license.KeyID).String(), nil
   170  }
   171  
   172  func doLoadLocalIssuedLicense(ctx context.Context, filename string, lclient licensing.Client) (*model.IssuedLicense, error) {
   173  	var license model.IssuedLicense
   174  	data, err := ioutil.ReadFile(filename)
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  	// The file may contain a leading BOM, which will choke the
   179  	// json deserializer.
   180  	data = bytes.TrimPrefix(data, []byte("\xef\xbb\xbf"))
   181  
   182  	err = json.Unmarshal(data, &license)
   183  	if err != nil {
   184  		return nil, errors.Wrap(err, "malformed license file")
   185  	}
   186  
   187  	_, err = lclient.VerifyLicense(ctx, license)
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  
   192  	return &license, nil
   193  }
   194  
   195  // ApplyLicense will store a license on the local system
   196  func ApplyLicense(ctx context.Context, dclient licensing.WrappedDockerClient, license *model.IssuedLicense) error {
   197  	info, err := dclient.Info(ctx)
   198  	if err != nil {
   199  		return err
   200  	}
   201  	return licensing.StoreLicense(ctx, dclient, license, info.DockerRootDir)
   202  }