github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/reconciler/client.go (about)

     1  package reconciler
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"net/http"
    10  	"time"
    11  
    12  	reconcilerApi "github.com/kyma-incubator/reconciler/pkg/keb"
    13  	kebError "github.com/kyma-project/kyma-environment-broker/internal/error"
    14  	"github.com/sirupsen/logrus"
    15  )
    16  
    17  //go:generate mockery --name=Client --output=automock --outpkg=automock --case=underscore
    18  
    19  type Client interface {
    20  	ApplyClusterConfig(cluster reconcilerApi.Cluster) (*reconcilerApi.HTTPClusterResponse, error)
    21  	DeleteCluster(clusterName string) error
    22  	GetCluster(clusterName string, configVersion int64) (*reconcilerApi.HTTPClusterResponse, error)
    23  	GetLatestCluster(clusterName string) (*reconcilerApi.HTTPClusterResponse, error)
    24  	GetStatusChange(clusterName, offset string) ([]*reconcilerApi.StatusChange, error)
    25  }
    26  
    27  type Config struct {
    28  	URL                 string
    29  	ProvisioningTimeout time.Duration `json:"default=2h"`
    30  }
    31  
    32  type client struct {
    33  	httpClient *http.Client
    34  	log        logrus.FieldLogger
    35  	config     *Config
    36  }
    37  
    38  func NewReconcilerClient(httpClient *http.Client, log logrus.FieldLogger, cfg *Config) *client {
    39  	return &client{
    40  		httpClient: httpClient,
    41  		log:        log,
    42  		config:     cfg,
    43  	}
    44  }
    45  
    46  // POST /v1/clusters
    47  func (c *client) ApplyClusterConfig(cluster reconcilerApi.Cluster) (*reconcilerApi.HTTPClusterResponse, error) {
    48  	reqBody, err := json.Marshal(cluster)
    49  	if err != nil {
    50  		c.log.Error(err)
    51  		return &reconcilerApi.HTTPClusterResponse{}, err
    52  	}
    53  
    54  	reader := bytes.NewReader(reqBody)
    55  
    56  	request, err := http.NewRequest("POST", fmt.Sprintf("%s/v1/clusters", c.config.URL), reader)
    57  	if err != nil {
    58  		c.log.Error(err)
    59  		return &reconcilerApi.HTTPClusterResponse{}, err
    60  	}
    61  
    62  	res, err := c.httpClient.Do(request)
    63  	if err != nil {
    64  		c.log.Error(err)
    65  		return &reconcilerApi.HTTPClusterResponse{}, kebError.NewTemporaryError(err.Error())
    66  	}
    67  	defer res.Body.Close()
    68  
    69  	c.log.Debugf("Got response: statusCode=%d", res.StatusCode)
    70  	switch {
    71  	case res.StatusCode == http.StatusOK || res.StatusCode == http.StatusCreated:
    72  	case res.StatusCode >= 400 && res.StatusCode < 500:
    73  		message, _ := io.ReadAll(res.Body)
    74  		logrus.Errorf("Reconciler response: %s", string(message))
    75  		return nil, httpStatusCodeError(res.StatusCode)
    76  	case res.StatusCode >= 500:
    77  		return nil, kebError.WrapNewTemporaryError(httpStatusCodeError(res.StatusCode))
    78  	}
    79  
    80  	registerClusterResponse, err := ioutil.ReadAll(res.Body)
    81  	if err != nil {
    82  		c.log.Error(err)
    83  		return &reconcilerApi.HTTPClusterResponse{}, err
    84  	}
    85  	var response *reconcilerApi.HTTPClusterResponse
    86  	err = json.Unmarshal(registerClusterResponse, &response)
    87  	if err != nil {
    88  		c.log.Error(err)
    89  		return &reconcilerApi.HTTPClusterResponse{}, err
    90  	}
    91  	return response, nil
    92  }
    93  
    94  // DELETE /v1/clusters/{clusterName}
    95  func (c *client) DeleteCluster(clusterName string) error {
    96  	request, err := http.NewRequest("DELETE", fmt.Sprintf("%s/v1/clusters/%s", c.config.URL, clusterName), nil)
    97  	if err != nil {
    98  		c.log.Error(err)
    99  		return err
   100  	}
   101  
   102  	res, err := c.httpClient.Do(request)
   103  	if err != nil {
   104  		c.log.Error(err)
   105  		return kebError.NewTemporaryError(err.Error())
   106  	}
   107  	switch {
   108  	case res.StatusCode == http.StatusNotFound:
   109  		return nil
   110  	case res.StatusCode >= 400 && res.StatusCode < 500 && res.StatusCode != http.StatusNotFound:
   111  		return httpStatusCodeError(res.StatusCode)
   112  	case res.StatusCode >= 500:
   113  		return kebError.WrapNewTemporaryError(httpStatusCodeError(res.StatusCode))
   114  	default:
   115  		return nil
   116  	}
   117  
   118  }
   119  
   120  // GET /v1/clusters/{clusterName}/configs/{configVersion}/status
   121  func (c *client) GetCluster(clusterName string, configVersion int64) (*reconcilerApi.HTTPClusterResponse, error) {
   122  	request, err := http.NewRequest("GET", fmt.Sprintf("%s/v1/clusters/%s/configs/%d/status", c.config.URL, clusterName, configVersion), nil)
   123  	if err != nil {
   124  		c.log.Error(err)
   125  		return &reconcilerApi.HTTPClusterResponse{}, err
   126  	}
   127  
   128  	res, err := c.httpClient.Do(request)
   129  	if err != nil {
   130  		c.log.Error(err)
   131  		return &reconcilerApi.HTTPClusterResponse{}, kebError.NewTemporaryError(err.Error())
   132  	}
   133  	defer res.Body.Close()
   134  	switch {
   135  	case res.StatusCode == http.StatusNotFound:
   136  		return &reconcilerApi.HTTPClusterResponse{}, kebError.NotFoundError{}
   137  	case res.StatusCode >= 400 && res.StatusCode < 500 && res.StatusCode != http.StatusNotFound:
   138  		return &reconcilerApi.HTTPClusterResponse{}, httpStatusCodeError(res.StatusCode)
   139  	case res.StatusCode >= 500:
   140  		return &reconcilerApi.HTTPClusterResponse{}, kebError.WrapNewTemporaryError(httpStatusCodeError(res.StatusCode))
   141  	}
   142  
   143  	getClusterResponse, err := ioutil.ReadAll(res.Body)
   144  	if err != nil {
   145  		c.log.Error(err)
   146  		return &reconcilerApi.HTTPClusterResponse{}, err
   147  	}
   148  	var response *reconcilerApi.HTTPClusterResponse
   149  	err = json.Unmarshal(getClusterResponse, &response)
   150  	if err != nil {
   151  		c.log.Error(err)
   152  		return &reconcilerApi.HTTPClusterResponse{}, err
   153  	}
   154  	return response, nil
   155  }
   156  
   157  // GET v1/clusters/{clusterName}/status
   158  func (c *client) GetLatestCluster(clusterName string) (*reconcilerApi.HTTPClusterResponse, error) {
   159  	request, err := http.NewRequest("GET", fmt.Sprintf("%s/v1/clusters/%s/status", c.config.URL, clusterName), nil)
   160  	if err != nil {
   161  		c.log.Error(err)
   162  		return &reconcilerApi.HTTPClusterResponse{}, err
   163  	}
   164  
   165  	res, err := c.httpClient.Do(request)
   166  	if err != nil {
   167  		c.log.Error(err)
   168  		return &reconcilerApi.HTTPClusterResponse{}, kebError.NewTemporaryError(err.Error())
   169  	}
   170  	defer res.Body.Close()
   171  
   172  	getClusterResponse, err := ioutil.ReadAll(res.Body)
   173  	if err != nil {
   174  		c.log.Error(err)
   175  		return &reconcilerApi.HTTPClusterResponse{}, err
   176  	}
   177  	var response *reconcilerApi.HTTPClusterResponse
   178  	err = json.Unmarshal(getClusterResponse, &response)
   179  	if err != nil {
   180  		c.log.Error(err)
   181  		return &reconcilerApi.HTTPClusterResponse{}, err
   182  	}
   183  	return response, nil
   184  }
   185  
   186  // GET v1/clusters/{clusterName}/statusChanges/{offset}
   187  // offset is parsed to time.Duration
   188  func (c *client) GetStatusChange(clusterName, offset string) ([]*reconcilerApi.StatusChange, error) {
   189  	request, err := http.NewRequest("GET", fmt.Sprintf("%s/v1/clusters/%s/statusChanges/%s", c.config.URL, clusterName, offset), nil)
   190  	if err != nil {
   191  		c.log.Error(err)
   192  		return []*reconcilerApi.StatusChange{}, err
   193  	}
   194  
   195  	res, err := c.httpClient.Do(request)
   196  	if err != nil {
   197  		c.log.Error(err)
   198  		return []*reconcilerApi.StatusChange{}, err
   199  	}
   200  	defer res.Body.Close()
   201  
   202  	getStatusChangeResponse, err := ioutil.ReadAll(res.Body)
   203  	if err != nil {
   204  		c.log.Error(err)
   205  		return []*reconcilerApi.StatusChange{}, err
   206  	}
   207  	var response []*reconcilerApi.StatusChange
   208  	err = json.Unmarshal(getStatusChangeResponse, &response)
   209  	if err != nil {
   210  		c.log.Error(err)
   211  		return []*reconcilerApi.StatusChange{}, err
   212  	}
   213  	return response, nil
   214  }
   215  
   216  func httpStatusCodeError(code int) kebError.LastError {
   217  	return kebError.LastError{}.
   218  		SetMessage(fmt.Sprintf("got status %d", code)).
   219  		SetReason(kebError.ErrHttpStatusCode).
   220  		SetComponent(kebError.ErrReconciler)
   221  }