github.com/jenkins-x/jx/v2@v2.1.155/pkg/cloud/iks/accounts.go (about)

     1  package iks
     2  
     3  // based on "github.com/IBM-Cloud/bluemix-go/account/accountv2 to add linkages
     4  
     5  import (
     6  	"fmt"
     7  	gohttp "net/http"
     8  
     9  	ibmcloud "github.com/IBM-Cloud/bluemix-go"
    10  	"github.com/IBM-Cloud/bluemix-go/api/account/accountv2"
    11  	"github.com/IBM-Cloud/bluemix-go/authentication"
    12  	"github.com/IBM-Cloud/bluemix-go/bmxerror"
    13  	"github.com/IBM-Cloud/bluemix-go/client"
    14  	"github.com/IBM-Cloud/bluemix-go/http"
    15  	"github.com/IBM-Cloud/bluemix-go/rest"
    16  	"github.com/IBM-Cloud/bluemix-go/session"
    17  )
    18  
    19  //Metadata ...
    20  type Metadata struct {
    21  	GUID string `json:"guid"`
    22  	URL  string `json:"url"`
    23  }
    24  
    25  //Resource ...
    26  type Resource struct {
    27  	Metadata Metadata
    28  }
    29  
    30  //Account Model ...
    31  type Account struct {
    32  	GUID          string
    33  	Name          string
    34  	Type          string
    35  	State         string
    36  	OwnerGUID     string
    37  	OwnerUserID   string
    38  	OwnerUniqueID string
    39  	CustomerID    string
    40  	CountryCode   string
    41  	CurrencyCode  string
    42  	Organizations []AccountOrganization
    43  	IMSAccountID  string
    44  }
    45  
    46  //AccountOrganization ...
    47  type AccountOrganization struct {
    48  	GUID   string `json:"guid"`
    49  	Region string `json:"region"`
    50  }
    51  
    52  type Linkage struct {
    53  	Origin string `json:"origin"`
    54  	State  string `json:"state"`
    55  }
    56  
    57  type BluemixSubscription struct {
    58  	SoftlayerAccountID string `json:"softlayer_account_id"`
    59  }
    60  
    61  //AccountResource ...
    62  type AccountResource struct {
    63  	Resource
    64  	Entity AccountEntity
    65  }
    66  
    67  //AccountEntity ...
    68  type AccountEntity struct {
    69  	Name                 string                `json:"name"`
    70  	Type                 string                `json:"type"`
    71  	State                string                `json:"state"`
    72  	OwnerGUID            string                `json:"owner"`
    73  	OwnerUserID          string                `json:"owner_userid"`
    74  	OwnerUniqueID        string                `json:"owner_unique_id"`
    75  	CustomerID           string                `json:"customer_id"`
    76  	CountryCode          string                `json:"country_code"`
    77  	CurrencyCode         string                `json:"currency_code"`
    78  	Organizations        []AccountOrganization `json:"organizations_region"`
    79  	Linkages             []Linkage             `json:"linkages"`
    80  	BluemixSubscriptions []BluemixSubscription `json:"bluemix_subscriptions"`
    81  }
    82  
    83  //AccountServiceAPI is the accountv2 client ...
    84  type AccountServiceAPI interface {
    85  	Accounts() Accounts
    86  }
    87  
    88  //MccpService holds the client
    89  type accountService struct {
    90  	*client.Client
    91  }
    92  
    93  //New ...
    94  func NewAccountServiceAPI(sess *session.Session) (AccountServiceAPI, error) {
    95  	config := sess.Config.Copy()
    96  	err := config.ValidateConfigForService(ibmcloud.AccountService)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  	if config.HTTPClient == nil {
   101  		config.HTTPClient = http.NewHTTPClient(config)
   102  	}
   103  	tokenRefreher, err := authentication.NewUAARepository(config, &rest.Client{
   104  		DefaultHeader: gohttp.Header{
   105  			"User-Agent": []string{http.UserAgent()},
   106  		},
   107  		HTTPClient: config.HTTPClient,
   108  	})
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	if config.UAAAccessToken == "" {
   113  		err := authentication.PopulateTokens(tokenRefreher, config)
   114  		if err != nil {
   115  			return nil, err
   116  		}
   117  	}
   118  	if config.Endpoint == nil {
   119  		ep, err := config.EndpointLocator.AccountManagementEndpoint()
   120  		if err != nil {
   121  			return nil, err
   122  		}
   123  		config.Endpoint = &ep
   124  	}
   125  	return &accountService{
   126  		Client: client.New(config, ibmcloud.AccountService, tokenRefreher),
   127  	}, nil
   128  }
   129  
   130  //Accounts API
   131  func (a *accountService) Accounts() Accounts {
   132  	return newAccountAPI(a.Client)
   133  }
   134  
   135  //ToModel ...
   136  func (resource AccountResource) ToModel() Account {
   137  	entity := resource.Entity
   138  	var imsAccountID string
   139  	for _, linkage := range entity.Linkages {
   140  		if (linkage.Origin == "IMS") && (linkage.State == "COMPLETE") {
   141  			for _, subscription := range entity.BluemixSubscriptions {
   142  				imsAccountID = subscription.SoftlayerAccountID
   143  			}
   144  		}
   145  	}
   146  	return Account{
   147  		GUID:          resource.Metadata.GUID,
   148  		Name:          entity.Name,
   149  		Type:          entity.Type,
   150  		State:         entity.State,
   151  		OwnerGUID:     entity.OwnerGUID,
   152  		OwnerUserID:   entity.OwnerUserID,
   153  		OwnerUniqueID: entity.OwnerUniqueID,
   154  		CustomerID:    entity.CustomerID,
   155  		CountryCode:   entity.CountryCode,
   156  		CurrencyCode:  entity.CurrencyCode,
   157  		Organizations: entity.Organizations,
   158  		IMSAccountID:  imsAccountID,
   159  	}
   160  }
   161  
   162  func (nameQueryResponse AccountNameQueryResponse) ToModel() Account {
   163  	entity := nameQueryResponse.Entity
   164  	guid := nameQueryResponse.Metadata.GUID
   165  
   166  	var imsAccountID string
   167  	for _, linkage := range entity.Linkages {
   168  		if (linkage.Origin == "IMS") && (linkage.State == "COMPLETE") {
   169  			for _, subscription := range entity.BluemixSubscriptions {
   170  				imsAccountID = subscription.SoftlayerAccountID
   171  			}
   172  		}
   173  	}
   174  	return Account{
   175  		GUID:          guid,
   176  		Name:          entity.Name,
   177  		Type:          entity.Type,
   178  		State:         entity.State,
   179  		OwnerGUID:     entity.OwnerGUID,
   180  		OwnerUserID:   entity.OwnerUserID,
   181  		OwnerUniqueID: entity.OwnerUniqueID,
   182  		CustomerID:    entity.CustomerID,
   183  		CountryCode:   entity.CountryCode,
   184  		CurrencyCode:  entity.CurrencyCode,
   185  		Organizations: entity.Organizations,
   186  		IMSAccountID:  imsAccountID,
   187  	}
   188  }
   189  
   190  //AccountQueryResponse ...
   191  type AccountQueryResponse struct {
   192  	Metadata Metadata
   193  	Accounts []AccountResource `json:"resources"`
   194  }
   195  
   196  //AccountQueryResponse ...
   197  type AccountNameQueryResponse struct {
   198  	Metadata Metadata
   199  	Entity   AccountEntity
   200  }
   201  
   202  //Accounts ...
   203  type Accounts interface {
   204  	List() ([]Account, error)
   205  	FindByOrg(orgGUID string, region string) (*Account, error)
   206  	FindByOwner(userID string) (*Account, error)
   207  	Get(accountId string) (*Account, error)
   208  }
   209  
   210  type account struct {
   211  	client *client.Client
   212  }
   213  
   214  func newAccountAPI(c *client.Client) Accounts {
   215  	return &account{
   216  		client: c,
   217  	}
   218  }
   219  
   220  //FindByOrg ...
   221  func (a *account) FindByOrg(orgGUID, region string) (*Account, error) {
   222  	type organizationRegion struct {
   223  		GUID   string `json:"guid"`
   224  		Region string `json:"region"`
   225  	}
   226  
   227  	payLoad := struct {
   228  		OrganizationsRegion []organizationRegion `json:"organizations_region"`
   229  	}{
   230  		OrganizationsRegion: []organizationRegion{
   231  			{
   232  				GUID:   orgGUID,
   233  				Region: region,
   234  			},
   235  		},
   236  	}
   237  
   238  	queryResp := AccountQueryResponse{}
   239  	response, err := a.client.Post("/coe/v2/getaccounts", payLoad, &queryResp)
   240  	if err != nil {
   241  
   242  		if response.StatusCode == 404 {
   243  			return nil, bmxerror.New(accountv2.ErrCodeNoAccountExists,
   244  				fmt.Sprintf("No account exists in the given region: %q and the given org: %q", region, orgGUID))
   245  		}
   246  		return nil, err
   247  
   248  	}
   249  
   250  	if len(queryResp.Accounts) > 0 {
   251  		account := queryResp.Accounts[0].ToModel()
   252  		return &account, nil
   253  	}
   254  
   255  	return nil, bmxerror.New(accountv2.ErrCodeNoAccountExists,
   256  		fmt.Sprintf("No account exists in the given region: %q and the given org: %q", region, orgGUID))
   257  }
   258  
   259  func (a *account) List() ([]Account, error) {
   260  	var accounts []Account
   261  	resp, err := a.client.GetPaginated("/coe/v2/accounts", accountv2.NewAccountPaginatedResources(AccountResource{}), func(resource interface{}) bool {
   262  		if accountResource, ok := resource.(AccountResource); ok {
   263  			accounts = append(accounts, accountResource.ToModel())
   264  			return true
   265  		}
   266  		return false
   267  	})
   268  
   269  	if resp.StatusCode == 404 || len(accounts) == 0 {
   270  		return nil, bmxerror.New(accountv2.ErrCodeNoAccountExists,
   271  			fmt.Sprintf("No Account exists"))
   272  	}
   273  
   274  	return accounts, err
   275  }
   276  
   277  //FindByOwner ...
   278  func (a *account) FindByOwner(userID string) (*Account, error) {
   279  	accounts, err := a.List()
   280  	if err != nil {
   281  		return nil, err
   282  	}
   283  
   284  	for _, a := range accounts {
   285  		if a.OwnerUserID == userID {
   286  			return &a, nil
   287  		}
   288  	}
   289  	return nil, bmxerror.New(accountv2.ErrCodeNoAccountExists,
   290  		fmt.Sprintf("No account exists for the user %q", userID))
   291  }
   292  
   293  //Get ...
   294  func (a *account) Get(accountId string) (*Account, error) {
   295  	queryResp := AccountNameQueryResponse{}
   296  	response, err := a.client.Get(fmt.Sprintf("/coe/v2/accounts/%s", accountId), &queryResp)
   297  	if err != nil {
   298  
   299  		if response.StatusCode == 404 {
   300  			return nil, bmxerror.New(accountv2.ErrCodeNoAccountExists,
   301  				fmt.Sprintf("Account %q does not exists", accountId))
   302  		}
   303  		return nil, err
   304  
   305  	}
   306  
   307  	account := queryResp.ToModel()
   308  	return &account, nil
   309  
   310  }