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  }