github.com/kyma-project/kyma-environment-broker@v0.0.1/common/director/client.go (about) 1 package director 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "github.com/kyma-incubator/compass/components/director/pkg/graphql" 9 kebError "github.com/kyma-project/kyma-environment-broker/internal/error" 10 machineGraph "github.com/machinebox/graphql" 11 "github.com/sirupsen/logrus" 12 "golang.org/x/oauth2/clientcredentials" 13 ) 14 15 const ( 16 // accountIDKey is a header key name for request send by graphQL client 17 accountIDKey = "tenant" 18 ) 19 20 //go:generate mockery --name=GraphQLClient --output=automock 21 type GraphQLClient interface { 22 Run(ctx context.Context, req *machineGraph.Request, resp interface{}) error 23 } 24 25 type Client struct { 26 graphQLClient GraphQLClient 27 queryProvider queryProvider 28 log logrus.FieldLogger 29 } 30 31 type ( 32 getURLResponse struct { 33 Result graphql.RuntimeExt `json:"result"` 34 } 35 36 runtimeLabelResponse struct { 37 Result *graphql.Label `json:"result"` 38 } 39 40 getRuntimeIdResponse struct { 41 Result graphql.RuntimePageExt `json:"result"` 42 } 43 ) 44 45 // NewDirectorClient returns new director client struct pointer 46 func NewDirectorClient(ctx context.Context, config Config, log logrus.FieldLogger) *Client { 47 cfg := clientcredentials.Config{ 48 ClientID: config.OauthClientID, 49 ClientSecret: config.OauthClientSecret, 50 TokenURL: config.OauthTokenURL, 51 Scopes: []string{config.OauthScope}, 52 } 53 httpClientOAuth := cfg.Client(ctx) 54 httpClientOAuth.Timeout = 30 * time.Second 55 56 graphQLClient := machineGraph.NewClient(config.URL, machineGraph.WithHTTPClient(httpClientOAuth)) 57 58 return &Client{ 59 graphQLClient: graphQLClient, 60 queryProvider: queryProvider{}, 61 log: log, 62 } 63 } 64 65 // SetLabel adds key-value label to a Runtime 66 func (dc *Client) SetLabel(accountID, runtimeID, key, value string) error { 67 query := dc.queryProvider.SetRuntimeLabel(runtimeID, key, value) 68 req := machineGraph.NewRequest(query) 69 req.Header.Add(accountIDKey, accountID) 70 71 dc.log.Info("Setup label in director") 72 response, err := dc.setLabelsInDirector(req) 73 if err != nil { 74 return fmt.Errorf("while setting %s Runtime label to value %s: %w", key, value, err) 75 } 76 77 if response.Result == nil { 78 return fmt.Errorf("failed to set %s Runtime label to value %s. Received nil response", key, value) 79 } 80 81 dc.log.Infof("Label %s:%s set correctly", response.Result.Key, response.Result.Value) 82 return nil 83 } 84 85 // GetRuntimeID fetches runtime ID with given label name from director component 86 func (dc *Client) GetRuntimeID(accountID, instanceID string) (string, error) { 87 query := dc.queryProvider.RuntimeForInstanceId(instanceID) 88 req := machineGraph.NewRequest(query) 89 req.Header.Add(accountIDKey, accountID) 90 91 dc.log.Info("Send request to director") 92 response, err := dc.getRuntimeIdFromDirector(req) 93 if err != nil { 94 return "", err 95 } 96 97 dc.log.Info("Extract the RuntimeID from the response") 98 return dc.getIDFromRuntime(&response.Result) 99 } 100 101 func (dc *Client) fetchURLFromDirector(req *machineGraph.Request) (*getURLResponse, error) { 102 var response getURLResponse 103 104 err := dc.graphQLClient.Run(context.Background(), req, &response) 105 if err != nil { 106 dc.log.Errorf("call to director failed: %s", err) 107 return &getURLResponse{}, kebError.AsTemporaryError(err, "while requesting to director client") 108 } 109 110 return &response, nil 111 } 112 113 func (dc *Client) setLabelsInDirector(req *machineGraph.Request) (*runtimeLabelResponse, error) { 114 var response runtimeLabelResponse 115 116 err := dc.graphQLClient.Run(context.Background(), req, &response) 117 if err != nil { 118 dc.log.Errorf("call to director failed: %s", err) 119 return &runtimeLabelResponse{}, kebError.AsTemporaryError(err, "while requesting to director client") 120 } 121 122 return &response, nil 123 } 124 125 func (dc *Client) getRuntimeIdFromDirector(req *machineGraph.Request) (*getRuntimeIdResponse, error) { 126 var response getRuntimeIdResponse 127 128 err := dc.graphQLClient.Run(context.Background(), req, &response) 129 if err != nil { 130 dc.log.Errorf("call to director failed: %s", err) 131 return &getRuntimeIdResponse{}, kebError.AsTemporaryError(err, "while requesting to director client") 132 } 133 134 return &response, nil 135 } 136 137 func (dc *Client) getIDFromRuntime(response *graphql.RuntimePageExt) (string, error) { 138 if response.Data == nil || len(response.Data) == 0 || response.Data[0] == nil { 139 return "", fmt.Errorf("got empty data from director response") 140 } 141 if len(response.Data) > 1 { 142 return "", fmt.Errorf("expected single runtime, got: %v", response.Data) 143 } 144 return response.Data[0].ID, nil 145 }