github.com/olli-ai/jx/v2@v2.0.400-0.20210921045218-14731b4dd448/pkg/cloud/iks/registry.go (about)

     1  package iks
     2  
     3  import (
     4  	b64 "encoding/base64"
     5  	"encoding/json"
     6  	"fmt"
     7  	gohttp "net/http"
     8  	"net/url"
     9  	"strconv"
    10  
    11  	"github.com/jenkins-x/jx-logging/pkg/log"
    12  
    13  	ibmcloud "github.com/IBM-Cloud/bluemix-go"
    14  	"github.com/IBM-Cloud/bluemix-go/authentication"
    15  	"github.com/IBM-Cloud/bluemix-go/bmxerror"
    16  	"github.com/IBM-Cloud/bluemix-go/client"
    17  	"github.com/IBM-Cloud/bluemix-go/http"
    18  	"github.com/IBM-Cloud/bluemix-go/rest"
    19  	"github.com/IBM-Cloud/bluemix-go/session"
    20  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    21  	"k8s.io/client-go/kubernetes"
    22  )
    23  
    24  type Config struct {
    25  	Auths map[string]*Auth `json:"auths,omitempty"`
    26  }
    27  
    28  type Auth struct {
    29  	Auth string `json:"auth,omitempty"`
    30  }
    31  
    32  type RegistryServiceAPI interface {
    33  	Registry() Registry
    34  }
    35  
    36  //MccpService holds the client
    37  type registry struct {
    38  	*client.Client
    39  }
    40  
    41  type AddTokenResponse struct {
    42  	Token string `json:"token"`
    43  }
    44  
    45  type Registry interface {
    46  	AddToken(account string, description string, permanent bool, write bool) (string, error)
    47  }
    48  
    49  var regionToEndpoint = map[string]string{
    50  	"us-south": "https://registry.ng.bluemix.net",
    51  	"us-east":  "https://registry.ng.bluemix.net",
    52  	"global":   "https://registry.bluemix.net",
    53  	"eu-gb":    "https://registry.eu-gb.bluemix.net",
    54  	"au-syd":   "https://registry.au-syd.bluemix.net",
    55  	"eu-de":    "https://registry.eu-de.bluemix.net",
    56  }
    57  
    58  const (
    59  	ErrCodeNotAuthorized        = "NotAuthorized"
    60  	ErrCodeUnableToAuthenticate = "UnableToAuthenticate"
    61  )
    62  
    63  func (a *registry) Registry() Registry {
    64  	return newRegistryAPI(a.Client)
    65  }
    66  
    67  func newRegistryAPI(c *client.Client) Registry {
    68  	return &registry{
    69  		Client: c,
    70  	}
    71  }
    72  
    73  // Try to use the regional registry used by the cluster
    74  // We will also set the corresponding secret for jenkins-x right away
    75  func GetClusterRegistry(kubeClient kubernetes.Interface) string {
    76  
    77  	registry := "registry.bluemix.net" // default to global
    78  	secretFromConfig, err := kubeClient.CoreV1().Secrets("default").Get("bluemix-default-secret-regional", metav1.GetOptions{})
    79  	if err != nil {
    80  		return ""
    81  	}
    82  	dockerConfig := &Config{}
    83  	err = json.Unmarshal(secretFromConfig.Data[".dockerconfigjson"], dockerConfig)
    84  	if err == nil {
    85  		for k := range dockerConfig.Auths {
    86  			registry = k
    87  		}
    88  	}
    89  	return registry
    90  }
    91  
    92  func GetRegistryConfigJSON(registry string) (string, error) {
    93  
    94  	//token :=
    95  	c := new(ibmcloud.Config)
    96  	accountID, err := ConfigFromJSON(c)
    97  	if err != nil {
    98  		return "", err
    99  	}
   100  
   101  	s, err := session.New(c)
   102  	if err != nil {
   103  		return "", err
   104  	}
   105  
   106  	registryAPI, err := NewRegistryServiceAPI(s)
   107  	registryIF := registryAPI.Registry()
   108  	clusterName, _ := GetClusterName()
   109  	token, err := registryIF.AddToken(accountID, fmt.Sprintf("%s Jenkins-X Token", clusterName), true, true)
   110  	if err != nil {
   111  		return "", err
   112  	}
   113  
   114  	newSecret := &Auth{}
   115  	dockerConfig := &Config{}
   116  	newSecret.Auth = b64.StdEncoding.EncodeToString([]byte("token:" + token))
   117  	if dockerConfig.Auths == nil {
   118  		dockerConfig.Auths = map[string]*Auth{}
   119  	}
   120  	dockerConfig.Auths[registry] = newSecret
   121  
   122  	configBytes, err := json.Marshal(dockerConfig)
   123  	if err != nil {
   124  		return "", err
   125  	}
   126  	return string(configBytes), nil
   127  }
   128  
   129  //New ...
   130  func NewRegistryServiceAPI(sess *session.Session) (RegistryServiceAPI, error) {
   131  	config := sess.Config.Copy()
   132  	if config.HTTPClient == nil {
   133  		config.HTTPClient = http.NewHTTPClient(config)
   134  	}
   135  	tokenRefreher, err := authentication.NewIAMAuthRepository(config, &rest.Client{
   136  		DefaultHeader: gohttp.Header{
   137  			"User-Agent": []string{http.UserAgent()},
   138  		},
   139  		HTTPClient: config.HTTPClient,
   140  	})
   141  	if err != nil {
   142  		return nil, err
   143  	}
   144  	if config.IAMAccessToken == "" {
   145  		err := authentication.PopulateTokens(tokenRefreher, config)
   146  		if err != nil {
   147  			return nil, err
   148  		}
   149  	}
   150  	if config.Endpoint == nil {
   151  		endpoint := regionToEndpoint[config.Region]
   152  		config.Endpoint = &endpoint
   153  	}
   154  
   155  	return &registry{
   156  		Client: client.New(config, ibmcloud.IAMService, tokenRefreher),
   157  	}, nil
   158  }
   159  
   160  func (a *registry) AddToken(accountID string, description string, permanent bool, write bool) (string, error) {
   161  	queryResp := AddTokenResponse{}
   162  	v := url.Values{}
   163  	v.Set("description", description)
   164  	v.Set("permanent", strconv.FormatBool(permanent))
   165  	v.Set("write", strconv.FormatBool(write))
   166  	m := make(map[string]string, 1)
   167  	m["Account"] = accountID
   168  
   169  	response, err := a.Client.Post(fmt.Sprintf("/api/v1/tokens?%s", v.Encode()), nil, &queryResp, m)
   170  	if err != nil {
   171  		log.Logger().Errorf("error - %s", err)
   172  		if response.StatusCode == 401 {
   173  			return "", bmxerror.New(ErrCodeNotAuthorized,
   174  				"You are not authorized to view the requested resource, or your IBM Cloud bearer token is invalid. Correct the request and try again.")
   175  		}
   176  		if response.StatusCode == 503 {
   177  			return "", bmxerror.New(ErrCodeUnableToAuthenticate,
   178  				"Unable to authenticate with IBM Cloud. Try again later.")
   179  		}
   180  		return "", err
   181  
   182  	}
   183  	return queryResp.Token, nil
   184  
   185  }