forked from kyma-project/control-plane
-
Notifications
You must be signed in to change notification settings - Fork 0
/
instance_update.go
146 lines (128 loc) · 5.46 KB
/
instance_update.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package broker
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"github.com/kyma-project/control-plane/components/kyma-environment-broker/internal"
"github.com/kyma-project/control-plane/components/kyma-environment-broker/internal/ptr"
"github.com/kyma-project/control-plane/components/kyma-environment-broker/internal/storage"
"github.com/kyma-project/control-plane/components/kyma-environment-broker/internal/storage/dberr"
"github.com/pivotal-cf/brokerapi/v7/domain"
"github.com/pivotal-cf/brokerapi/v7/domain/apiresponses"
"github.com/sirupsen/logrus"
)
type ContextUpdateHandler interface {
Handle(instance *internal.Instance, newCtx internal.ERSContext) error
}
type UpdateEndpoint struct {
log logrus.FieldLogger
instanceStorage storage.Instances
contextUpdateHandler ContextUpdateHandler
processingEnabled bool
operationStorage storage.Operations
}
func NewUpdate(instanceStorage storage.Instances, operationStorage storage.Operations, ctxUpdateHandler ContextUpdateHandler, processingEnabled bool, log logrus.FieldLogger) *UpdateEndpoint {
return &UpdateEndpoint{
log: log.WithField("service", "UpdateEndpoint"),
instanceStorage: instanceStorage,
operationStorage: operationStorage,
contextUpdateHandler: ctxUpdateHandler,
processingEnabled: processingEnabled,
}
}
// Update modifies an existing service instance
// PATCH /v2/service_instances/{instance_id}
func (b *UpdateEndpoint) Update(ctx context.Context, instanceID string, details domain.UpdateDetails, asyncAllowed bool) (domain.UpdateServiceSpec, error) {
logger := b.log.WithField("instanceID", instanceID)
logger.Infof("Update instanceID: %s", instanceID)
logger.Infof("Update asyncAllowed: %v", asyncAllowed)
instance, err := b.instanceStorage.GetByID(instanceID)
if err != nil && dberr.IsNotFound(err) {
logger.Errorf("unable to get instance: %s", err.Error())
return domain.UpdateServiceSpec{}, apiresponses.NewFailureResponse(err, http.StatusNotFound, fmt.Sprintf("could not execute update for instanceID %s", instanceID))
} else if err != nil {
logger.Errorf("unable to get instance: %s", err.Error())
return domain.UpdateServiceSpec{}, errors.New("unable to get instance")
}
logger.Infof("Plan ID/Name: %s/%s", instance.ServicePlanID, PlanNamesMapping[instance.ServicePlanID])
var ersContext internal.ERSContext
err = json.Unmarshal(details.RawContext, &ersContext)
if err != nil {
logger.Errorf("unable to decode context: %s", err.Error())
return domain.UpdateServiceSpec{}, errors.New("unable to unmarshal context")
}
logger.Infof("Global account ID: %s active: %s", instance.GlobalAccountID, ptr.BoolAsString(ersContext.Active))
var contextData map[string]interface{}
err = json.Unmarshal(details.RawContext, &contextData)
if err != nil {
logger.Errorf("unable to unmarshal context: %s", err.Error())
return domain.UpdateServiceSpec{}, errors.New("unable to unmarshal context")
}
logger.Infof("Context with keys:")
for k, _ := range contextData {
logger.Info(k)
}
if b.processingEnabled {
// todo: remove the code below when we are sure the ERSContext contains required values.
// This code is done because the PATCH request contains only some of fields and that requests made the ERS context empty in the past.
provOperation, err := b.operationStorage.GetProvisioningOperationByInstanceID(instanceID)
if err != nil {
logger.Errorf("processing context updated failed: %s", err.Error())
return domain.UpdateServiceSpec{
IsAsync: false,
DashboardURL: instance.DashboardURL,
OperationData: "",
}, errors.New("unable to process the update")
}
instance.Parameters.ErsContext = provOperation.ProvisioningParameters.ErsContext
instance.Parameters.ErsContext.Active, err = b.exctractActiveValue(instance.InstanceID, *provOperation)
if err != nil {
return domain.UpdateServiceSpec{
IsAsync: false,
DashboardURL: instance.DashboardURL,
OperationData: "",
}, errors.New("unable to process the update")
}
err = b.contextUpdateHandler.Handle(instance, ersContext)
if err != nil {
logger.Errorf("processing context updated failed: %s", err.Error())
return domain.UpdateServiceSpec{
IsAsync: false,
DashboardURL: instance.DashboardURL,
OperationData: "",
}, errors.New("unable to process the update")
}
// copy the Active flag if set
if ersContext.Active != nil {
instance.Parameters.ErsContext.Active = ersContext.Active
}
_, err = b.instanceStorage.Update(*instance)
if err != nil {
logger.Errorf("processing context updated failed: %s", err.Error())
return domain.UpdateServiceSpec{
IsAsync: false,
DashboardURL: instance.DashboardURL,
OperationData: "",
}, errors.New("unable to process the update")
}
}
return domain.UpdateServiceSpec{
IsAsync: false,
DashboardURL: instance.DashboardURL,
OperationData: "",
}, nil
}
func (b *UpdateEndpoint) exctractActiveValue(id string, provisioning internal.ProvisioningOperation) (*bool, error) {
deprovisioning, dErr := b.operationStorage.GetDeprovisioningOperationByInstanceID(id)
if dErr != nil && !dberr.IsNotFound(dErr) {
b.log.Errorf("Unable to get deprovisioning operation for the instance %s to check the active flag: %s", id, dErr.Error())
return nil, dErr
}
// there was no any deprovisioning in the past (any suspension)
if deprovisioning == nil {
return ptr.Bool(true), nil
}
return ptr.Bool(deprovisioning.CreatedAt.Before(provisioning.CreatedAt)), nil
}