Skip to content

Commit

Permalink
Merge branch 'main' into update_diagrams
Browse files Browse the repository at this point in the history
  • Loading branch information
jaroslaw-pieszka authored Nov 14, 2024
2 parents 693e8d6 + b1512ed commit 38dbc13
Show file tree
Hide file tree
Showing 6 changed files with 280 additions and 23 deletions.
75 changes: 75 additions & 0 deletions cmd/broker/binding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,81 @@ func TestDeprovisioningWithExistingBindings(t *testing.T) {
suite.AssertBindingRemoval(iid, bindingID2)
}

func TestFailedProvisioning(t *testing.T) {
// given
cfg := fixConfig()
// Disable EDP to have all steps successfully executed
cfg.EDP.Disabled = true
suite := NewBrokerSuiteTestWithConfig(t, cfg)
defer suite.TearDown()
iid := uuid.New().String()
bindingID1 := uuid.New().String()

response := suite.CallAPI(http.MethodPut, fmt.Sprintf("oauth/v2/service_instances/%s?accepts_incomplete=true", iid),
`{
"service_id": "47c9dcbf-ff30-448e-ab36-d3bad66ba281",
"plan_id": "361c511f-f939-4621-b228-d0fb79a1fe15",
"context": {
"globalaccount_id": "g-account-id",
"subaccount_id": "sub-id",
"user_id": "[email protected]"
},
"parameters": {
"name": "testing-cluster",
"region": "eu-central-1"
}
}`)
opID := suite.DecodeOperationID(response)
suite.failProvisioningByOperationID(opID)

// when we create binding
response = suite.CallAPI(http.MethodPut, fmt.Sprintf("oauth/v2/service_instances/%s/service_bindings/%s", iid, bindingID1),
`{
"service_id": "47c9dcbf-ff30-448e-ab36-d3bad66ba281",
"plan_id": "361c511f-f939-4621-b228-d0fb79a1fe15"
}`)

// then expect 400 as agreed in the contract
require.Equal(t, http.StatusBadRequest, response.StatusCode)
}

func TestProvisioningInProgress(t *testing.T) {
// given
cfg := fixConfig()
// Disable EDP to have all steps successfully executed
cfg.EDP.Disabled = true
suite := NewBrokerSuiteTestWithConfig(t, cfg)
defer suite.TearDown()
iid := uuid.New().String()
bindingID1 := uuid.New().String()

response := suite.CallAPI(http.MethodPut, fmt.Sprintf("oauth/v2/service_instances/%s?accepts_incomplete=true", iid),
`{
"service_id": "47c9dcbf-ff30-448e-ab36-d3bad66ba281",
"plan_id": "361c511f-f939-4621-b228-d0fb79a1fe15",
"context": {
"globalaccount_id": "g-account-id",
"subaccount_id": "sub-id",
"user_id": "[email protected]"
},
"parameters": {
"name": "testing-cluster",
"region": "eu-central-1"
}
}`)
opID := suite.DecodeOperationID(response)
suite.WaitForProvisioningState(opID, domain.InProgress)
// when we create binding
response = suite.CallAPI(http.MethodPut, fmt.Sprintf("oauth/v2/service_instances/%s/service_bindings/%s", iid, bindingID1),
`{
"service_id": "47c9dcbf-ff30-448e-ab36-d3bad66ba281",
"plan_id": "361c511f-f939-4621-b228-d0fb79a1fe15"
}`)

// then expect 400 as agreed in the contract
require.Equal(t, http.StatusBadRequest, response.StatusCode)
}

func TestRemoveBindingsFromSuspended(t *testing.T) {
// given
cfg := fixConfig()
Expand Down
27 changes: 24 additions & 3 deletions internal/broker/bind_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ type BindingConfig struct {
}

type BindEndpoint struct {
config BindingConfig
instancesStorage storage.Instances
bindingsStorage storage.Bindings
config BindingConfig
instancesStorage storage.Instances
bindingsStorage storage.Bindings
operationsStorage storage.Operations

serviceAccountBindingManager broker.BindingsManager
publisher event.Publisher
Expand Down Expand Up @@ -74,6 +75,7 @@ func NewBind(cfg BindingConfig, db storage.BrokerStorage, log logrus.FieldLogger
instancesStorage: db.Instances(),
bindingsStorage: db.Bindings(),
publisher: publisher,
operationsStorage: db.Operations(),
log: log.WithField("service", "BindEndpoint"),
serviceAccountBindingManager: broker.NewServiceAccountBindingsManager(clientProvider, kubeconfigProvider),
}
Expand Down Expand Up @@ -149,6 +151,20 @@ func (b *BindEndpoint) bind(ctx context.Context, instanceID, bindingID string, d
expirationSeconds = parameters.ExpirationSeconds
}

lastOperation, err := b.operationsStorage.GetLastOperation(instance.InstanceID)
if err != nil {
return domain.Binding{}, apiresponses.NewFailureResponse(fmt.Errorf("failed to get last operation for instance %s", instanceID), http.StatusInternalServerError, fmt.Sprintf("failed to get last operation %s", instanceID))
}
if lastOperation.Type == internal.OperationTypeProvision && (lastOperation.State == domain.InProgress || lastOperation.State == domain.Failed) {
var message string
if lastOperation.State == domain.InProgress {
message = fmt.Sprintf("instance %s creation is in progress", instanceID)
} else {
message = fmt.Sprintf("instance %s creation failed", instanceID)
}
return domain.Binding{}, apiresponses.NewFailureResponse(fmt.Errorf(message), http.StatusBadRequest, message) // Agreed with Provisioning API team to return 400
}

bindingFromDB, err := b.bindingsStorage.Get(instanceID, bindingID)
if err != nil && !dberr.IsNotFound(err) {
message := fmt.Sprintf("failed to get Kyma binding from storage: %s", err)
Expand All @@ -160,6 +176,10 @@ func (b *BindEndpoint) bind(ctx context.Context, instanceID, bindingID string, d
return domain.Binding{}, apiresponses.NewFailureResponse(fmt.Errorf(message), http.StatusConflict, message)
}
if bindingFromDB.ExpiresAt.After(time.Now()) {
if len(bindingFromDB.Kubeconfig) == 0 {
message := fmt.Sprintf("binding creation already in progress")
return domain.Binding{}, apiresponses.NewFailureResponse(fmt.Errorf(message), http.StatusUnprocessableEntity, message)
}
return domain.Binding{
IsAsync: false,
AlreadyExists: true,
Expand All @@ -173,6 +193,7 @@ func (b *BindEndpoint) bind(ctx context.Context, instanceID, bindingID string, d
}
}

//TODO we get here if binding is not found in storage or it is expired
bindingList, err := b.bindingsStorage.ListByInstanceID(instanceID)
if err != nil {
message := fmt.Sprintf("failed to list Kyma bindings: %s", err)
Expand Down
131 changes: 111 additions & 20 deletions internal/broker/bind_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"fmt"
"net/http/httptest"
"testing"
"time"

Expand All @@ -23,26 +22,11 @@ import (
"github.com/stretchr/testify/require"
)

type Kubeconfig struct {
Users []User `yaml:"users"`
}

type User struct {
Name string `yaml:"name"`
User struct {
Token string `yaml:"token"`
} `yaml:"user"`
}

const (
instanceID1 = "1"
instanceID2 = "2"
instanceID3 = "max-bindings"
maxBindingsCount = 10
)

var httpServer *httptest.Server

type provider struct {
}

Expand Down Expand Up @@ -76,10 +60,8 @@ func TestCreateBindingEndpoint(t *testing.T) {
err := db.Instances().Insert(fixture.FixInstance(instanceID1))
require.NoError(t, err)

err = db.Instances().Insert(fixture.FixInstance(instanceID2))
require.NoError(t, err)

err = db.Instances().Insert(fixture.FixInstance(instanceID3))
operation := fixture.FixOperation("operation-id", instanceID1, "provision")
err = db.Operations().InsertOperation(operation)
require.NoError(t, err)

//// binding configuration
Expand Down Expand Up @@ -180,6 +162,7 @@ func TestCreateSecondBindingWithTheSameIdButDifferentParams(t *testing.T) {
instanceID := uuid.New().String()
bindingID := uuid.New().String()
instance := fixture.FixInstance(instanceID)
operation := fixture.FixOperation("operation-id", instanceID, "provision")
bindingCfg := &BindingConfig{
Enabled: true,
BindablePlans: EnablePlans{
Expand All @@ -196,6 +179,8 @@ func TestCreateSecondBindingWithTheSameIdButDifferentParams(t *testing.T) {
assert.NoError(t, err)
err = brokerStorage.Bindings().Insert(&binding)
assert.NoError(t, err)
err = brokerStorage.Operations().InsertOperation(operation)
assert.NoError(t, err)

publisher := event.NewPubSub(logrus.New())

Expand Down Expand Up @@ -223,6 +208,8 @@ func TestCreateSecondBindingWithTheSameIdAndParams(t *testing.T) {
instanceID := uuid.New().String()
bindingID := uuid.New().String()
instance := fixture.FixInstance(instanceID)
operation := fixture.FixOperation("operation-id", instanceID, "provision")

bindingCfg := &BindingConfig{
Enabled: true,
BindablePlans: EnablePlans{
Expand All @@ -239,6 +226,8 @@ func TestCreateSecondBindingWithTheSameIdAndParams(t *testing.T) {
assert.NoError(t, err)
err = brokerStorage.Bindings().Insert(&binding)
assert.NoError(t, err)
err = brokerStorage.Operations().InsertOperation(operation)
assert.NoError(t, err)

publisher := event.NewPubSub(logrus.New())

Expand All @@ -260,12 +249,112 @@ func TestCreateSecondBindingWithTheSameIdAndParams(t *testing.T) {
assert.Equal(t, binding.ExpiresAt.Format(expiresAtLayout), resp.Metadata.ExpiresAt)
}

func TestCreateSecondBindingWithTheSameIdAndParamsForExpired(t *testing.T) {
// given
const expiresAtLayout = "2006-01-02T15:04:05.0Z"
instanceID := uuid.New().String()
bindingID := uuid.New().String()
instance := fixture.FixInstance(instanceID)
operation := fixture.FixOperation("operation-id", instanceID, "provision")

bindingCfg := &BindingConfig{
Enabled: true,
BindablePlans: EnablePlans{
instance.ServicePlanName,
},
ExpirationSeconds: 600,
MaxExpirationSeconds: 7200,
MinExpirationSeconds: 600,
MaxBindingsCount: 10,
}
binding := fixture.FixExpiredBindingWithInstanceID(bindingID, instanceID, time.Minute*15)
brokerStorage := storage.NewMemoryStorage()
err := brokerStorage.Instances().Insert(instance)
assert.NoError(t, err)
err = brokerStorage.Bindings().Insert(&binding)
assert.NoError(t, err)
err = brokerStorage.Operations().InsertOperation(operation)
assert.NoError(t, err)

// event publisher
publisher := event.NewPubSub(logrus.New())

svc := NewBind(*bindingCfg, brokerStorage, logrus.New(), nil, nil, publisher)
params := BindingParams{
ExpirationSeconds: 600,
}
rawParams, err := json.Marshal(params)
assert.NoError(t, err)
details := domain.BindDetails{
RawParameters: rawParams,
}

// when
_, err = svc.Bind(context.Background(), instanceID, bindingID, details, false)

// then
require.Error(t, err)
assert.Contains(t, err.Error(), "failed to insert Kyma binding into storage")
}

func TestCreateSecondBindingWithTheSameIdAndParamsForBindingInProgress(t *testing.T) {
// given
const expiresAtLayout = "2006-01-02T15:04:05.0Z"
instanceID := uuid.New().String()
bindingID := uuid.New().String()
instance := fixture.FixInstance(instanceID)
operation := fixture.FixOperation("operation-id", instanceID, "provision")

bindingCfg := &BindingConfig{
Enabled: true,
BindablePlans: EnablePlans{
instance.ServicePlanName,
},
ExpirationSeconds: 600,
MaxExpirationSeconds: 7200,
MinExpirationSeconds: 600,
MaxBindingsCount: 10,
}

binding := fixture.FixBindingWithInstanceID(bindingID, instanceID)
binding.Kubeconfig = ""
brokerStorage := storage.NewMemoryStorage()
err := brokerStorage.Instances().Insert(instance)
assert.NoError(t, err)
err = brokerStorage.Bindings().Insert(&binding)
assert.NoError(t, err)
err = brokerStorage.Operations().InsertOperation(operation)
assert.NoError(t, err)

// event publisher
publisher := event.NewPubSub(logrus.New())

svc := NewBind(*bindingCfg, brokerStorage, logrus.New(), nil, nil, publisher)
params := BindingParams{
ExpirationSeconds: 600,
}
rawParams, err := json.Marshal(params)
assert.NoError(t, err)
details := domain.BindDetails{
RawParameters: rawParams,
}

// when
_, err = svc.Bind(context.Background(), instanceID, bindingID, details, false)

// then
require.Error(t, err)
assert.Contains(t, err.Error(), "binding creation already in progress")
}

func TestCreateSecondBindingWithTheSameIdAndParamsNotExplicitlyDefined(t *testing.T) {
// given
const expiresAtLayout = "2006-01-02T15:04:05.0Z"
instanceID := uuid.New().String()
bindingID := uuid.New().String()
instance := fixture.FixInstance(instanceID)
operation := fixture.FixOperation("operation-id", instanceID, "provision")

bindingCfg := &BindingConfig{
Enabled: true,
BindablePlans: EnablePlans{
Expand All @@ -282,6 +371,8 @@ func TestCreateSecondBindingWithTheSameIdAndParamsNotExplicitlyDefined(t *testin
assert.NoError(t, err)
err = brokerStorage.Bindings().Insert(&binding)
assert.NoError(t, err)
err = brokerStorage.Operations().InsertOperation(operation)
assert.NoError(t, err)

publisher := event.NewPubSub(logrus.New())

Expand Down
5 changes: 5 additions & 0 deletions internal/broker/bind_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ func (b *GetBindingEndpoint) GetBinding(_ context.Context, instanceID, bindingID
return domain.GetBindingSpec{}, apiresponses.NewFailureResponse(fmt.Errorf(message), http.StatusNotFound, message)
}

if len(binding.Kubeconfig) == 0 {
message := "Binding creation in progress"
return domain.GetBindingSpec{}, apiresponses.NewFailureResponse(fmt.Errorf(message), http.StatusNotFound, message)
}

if err != nil {
b.log.Errorf("GetBinding error: %s", err)
message := fmt.Sprintf("Unexpected error: %s", err)
Expand Down
Loading

0 comments on commit 38dbc13

Please sign in to comment.