Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clients/cfrestclient/cloud_foundry_operations_extended.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ type CloudFoundryOperationsExtended interface {
GetApplicationRoutes(appGuid string) ([]models.ApplicationRoute, error)
GetServiceInstances(mtaId, mtaNamespace, spaceGuid string) ([]models.CloudFoundryServiceInstance, error)
GetServiceBindings(serviceName string) ([]models.ServiceBinding, error)
GetServiceInstanceByName(serviceName, spaceGuid string) (models.CloudFoundryServiceInstance, error)
CreateUserProvidedServiceInstance(serviceName string, spaceGuid string, credentials map[string]string) (models.CloudFoundryServiceInstance, error)
}
8 changes: 8 additions & 0 deletions clients/cfrestclient/fakes/fake_cloud_foundry_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,11 @@ func (f FakeCloudFoundryClient) GetServiceInstances(mtaId, mtaNamespace, spaceGu
func (f FakeCloudFoundryClient) GetServiceBindings(serviceName string) ([]models.ServiceBinding, error) {
return f.ServiceBindings, f.ServiceBindingsErr
}

func (f FakeCloudFoundryClient) GetServiceInstanceByName(serviceName, spaceGuid string) (models.CloudFoundryServiceInstance, error) {
return f.Services[0], f.ServiceBindingsErr
}

func (f FakeCloudFoundryClient) CreateUserProvidedServiceInstance(serviceName string, spaceGuid string, credentials map[string]string) (models.CloudFoundryServiceInstance, error) {
return f.Services[0], f.ServicesErr
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package resilient

import (
"time"

"github.com/cloudfoundry-incubator/multiapps-cli-plugin/clients/cfrestclient"
"github.com/cloudfoundry-incubator/multiapps-cli-plugin/clients/models"
"time"
)

type ResilientCloudFoundryRestClient struct {
Expand Down Expand Up @@ -46,6 +47,18 @@ func (c ResilientCloudFoundryRestClient) GetServiceBindings(serviceName string)
}, c.MaxRetriesCount, c.RetryInterval)
}

func (c ResilientCloudFoundryRestClient) GetServiceInstanceByName(serviceName, spaceGuid string) (models.CloudFoundryServiceInstance, error) {
return retryOnError(func() (models.CloudFoundryServiceInstance, error) {
return c.CloudFoundryRestClient.GetServiceInstanceByName(serviceName, spaceGuid)
}, c.MaxRetriesCount, c.RetryInterval)
}

func (c ResilientCloudFoundryRestClient) CreateUserProvidedServiceInstance(serviceName string, spaceGuid string, credentials map[string]string) (models.CloudFoundryServiceInstance, error) {
return retryOnError(func() (models.CloudFoundryServiceInstance, error) {
return c.CloudFoundryRestClient.CreateUserProvidedServiceInstance(serviceName, spaceGuid, credentials)
}, c.MaxRetriesCount, c.RetryInterval)
}

func retryOnError[T any](operation func() (T, error), retries int, retryInterval time.Duration) (T, error) {
result, err := operation()
for shouldRetry(retries, err) {
Expand Down
100 changes: 93 additions & 7 deletions clients/cfrestclient/rest_cloud_foundry_client_extended.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cfrestclient

import (
"bytes"
"crypto/md5"
"crypto/tls"
"encoding/hex"
Expand Down Expand Up @@ -60,7 +61,7 @@ func (c CloudFoundryRestClient) GetAppProcessStatistics(appGuid string) ([]model
apiEndpoint, _ := c.cliConn.ApiEndpoint()

getAppProcessStatsUrl := fmt.Sprintf("%s/%sapps/%s/processes/web/stats", apiEndpoint, cfBaseUrl, appGuid)
body, err := executeRequest(getAppProcessStatsUrl, token, c.isSslDisabled)
body, err := executeRequest(http.MethodGet, getAppProcessStatsUrl, token, c.isSslDisabled, nil)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -114,10 +115,82 @@ func (c CloudFoundryRestClient) GetServiceBindings(serviceName string) ([]models
return getPaginatedResourcesWithIncluded(getServiceBindingsUrl, token, c.isSslDisabled, buildServiceBinding)
}

func (c CloudFoundryRestClient) GetServiceInstanceByName(serviceName, spaceGuid string) (models.CloudFoundryServiceInstance, error) {
token, err := c.cliConn.AccessToken()
if err != nil {
return models.CloudFoundryServiceInstance{}, fmt.Errorf("failed to retrieve access token: %s", err)
}
apiEndpoint, _ := c.cliConn.ApiEndpoint()

getServicesUrl := fmt.Sprintf("%s/%sservice_instances?names=%s&space_guids=%s",
apiEndpoint, cfBaseUrl, serviceName, spaceGuid)
services, err := getPaginatedResourcesWithIncluded(getServicesUrl, token, c.isSslDisabled, buildServiceInstance)
if err != nil {
return models.CloudFoundryServiceInstance{}, err
}
if len(services) == 0 {
return models.CloudFoundryServiceInstance{}, fmt.Errorf("service instance not found")
}

resultService := services[0]
return resultService, nil
}

func (c CloudFoundryRestClient) CreateUserProvidedServiceInstance(serviceName string, spaceGuid string, credentials map[string]string) (models.CloudFoundryServiceInstance, error) {
token, err := c.cliConn.AccessToken()
if err != nil {
return models.CloudFoundryServiceInstance{}, fmt.Errorf("failed to retrieve access token: %s", err)
}

apiEndpoint, _ := c.cliConn.ApiEndpoint()

createServiceURL := fmt.Sprintf("%s/%sservice_instances", apiEndpoint, cfBaseUrl)

payload := map[string]any{
"type": "user-provided",
"name": serviceName,
"relationships": map[string]any{
"space": map[string]any{
"data": map[string]any{
"guid": spaceGuid,
},
},
},
}

if credentials != nil {
payload["credentials"] = credentials
}

jsonBody, err := json.Marshal(payload)
if err != nil {
return models.CloudFoundryServiceInstance{}, fmt.Errorf("failed to marshal create UPS request: %w", err)
}

body, err := executeRequest(http.MethodPost, createServiceURL, token, c.isSslDisabled, jsonBody)
if err != nil {
return models.CloudFoundryServiceInstance{}, err
}

response, err := parseBody[models.CloudFoundryUserProvidedServiceInstance](body)
if err != nil {
return models.CloudFoundryServiceInstance{}, err
}

return models.CloudFoundryServiceInstance{
Guid: response.Guid,
Name: response.Name,
Type: response.Type,
LastOperation: response.LastOperation,
SpaceGuid: response.SpaceGuid,
Metadata: response.Metadata,
}, nil
}

func getPaginatedResources[T any](url, token string, isSslDisabled bool) ([]T, error) {
var result []T
for url != "" {
body, err := executeRequest(url, token, isSslDisabled)
body, err := executeRequest(http.MethodGet, url, token, isSslDisabled, nil)
if err != nil {
return nil, err
}
Expand All @@ -137,7 +210,7 @@ func getPaginatedResources[T any](url, token string, isSslDisabled bool) ([]T, e
func getPaginatedResourcesWithIncluded[T any, Auxiliary any](url, token string, isSslDisabled bool, auxiliaryContentHandler func(T, Auxiliary) T) ([]T, error) {
var result []T
for url != "" {
body, err := executeRequest(url, token, isSslDisabled)
body, err := executeRequest(http.MethodGet, url, token, isSslDisabled, nil)
if err != nil {
return nil, err
}
Expand All @@ -154,9 +227,22 @@ func getPaginatedResourcesWithIncluded[T any, Auxiliary any](url, token string,
return result, nil
}

func executeRequest(url, token string, isSslDisabled bool) ([]byte, error) {
req, _ := http.NewRequest(http.MethodGet, url, nil)
req.Header.Add("Authorization", token)
func executeRequest(methodType, url, token string, isSslDisabled bool, body []byte) ([]byte, error) {
var reader io.Reader

if body != nil {
reader = bytes.NewReader(body)
}
request, err := http.NewRequest(methodType, url, reader)
if err != nil {
return nil, err
}

request.Header.Add("Authorization", token)
request.Header.Set("Accept", "application/json")
if body != nil {
request.Header.Set("Content-Type", "application/json")
}

// Create transport with TLS configuration
httpTransport := http.DefaultTransport.(*http.Transport).Clone()
Expand All @@ -166,7 +252,7 @@ func executeRequest(url, token string, isSslDisabled bool) ([]byte, error) {
userAgentTransport := baseclient.NewUserAgentTransport(httpTransport)

client := &http.Client{Transport: userAgentTransport}
resp, err := client.Do(req)
resp, err := client.Do(request)
if err != nil {
return nil, err
}
Expand Down
9 changes: 9 additions & 0 deletions clients/models/cf_services_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ type CloudFoundryServiceInstance struct {
Offering ServiceOffering `json:"-"`
}

type CloudFoundryUserProvidedServiceInstance struct {
Guid string `json:"guid"`
Name string `json:"name"`
Type string `json:"type"`
LastOperation LastOperation `json:"last_operation,omitempty"`
SpaceGuid string `jsonry:"relationships.space.data.guid"`
Metadata Metadata `json:"metadata"`
}

type LastOperation struct {
Type string `json:"type"`
State string `json:"state"`
Expand Down
1 change: 1 addition & 0 deletions clients/mtaclient/mta_rest_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type AsyncUploadJobResult struct {
Error string `json:"error,omitempty"`
File *models.FileMetadata `json:"file,omitempty"`
MtaId string `json:"mta_id,omitempty"`
SchemaVersion string `json:"schema_version,omitempty"`
BytesProcessed int64 `json:"bytes_processed,omitempty"`
ClientActions []string `json:"client_actions,omitempty"`
}
Expand Down
2 changes: 1 addition & 1 deletion commands/blue_green_deploy_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type BlueGreenDeployCommand struct {
// NewBlueGreenDeployCommand creates a new BlueGreenDeployCommand.
func NewBlueGreenDeployCommand() *BlueGreenDeployCommand {
baseCmd := &BaseCommand{flagsParser: deployCommandLineArgumentsParser{}, flagsValidator: deployCommandFlagsValidator{}}
deployCmd := &DeployCommand{baseCmd, blueGreenDeployProcessParametersSetter(), &blueGreenDeployCommandProcessTypeProvider{}, os.Stdin, 30 * time.Second}
deployCmd := &DeployCommand{baseCmd, blueGreenDeployProcessParametersSetter(), &blueGreenDeployCommandProcessTypeProvider{}, os.Stdin, 30 * time.Second, nil}
bgDeployCmd := &BlueGreenDeployCommand{deployCmd}
baseCmd.Command = bgDeployCmd
return bgDeployCmd
Expand Down
Loading
Loading