github.com/kyma-project/kyma-environment-broker@v0.0.1/docs/user/03-20-runtime-operations.md (about)

     1  # SAP BTP, Kyma runtime operations
     2  
     3  Kyma Environment Broker (KEB) allows you to configure operations that you can run on a SAP BTP, Kyma runtime. Each operation consists of several steps and each step is represented by a separate file. As every step can be re-launched multiple times, for each step, you should determine a behavior in case of a processing failure. It can either:
     4  
     5  - Return an error, which interrupts the entire process, or
     6  - Repeat the entire operation after the specified period.
     7  
     8  > **NOTE:** It's important to set lower timeouts for the Kyma installation in the Runtime Provisioner.
     9  
    10  ## Provision
    11  
    12  The provisioning process is executed when the instance is created, or an unsuspension is triggered.
    13  Each provisioning step is responsible for a separate part of preparing Kyma runtime. For example, in a step you can provide tokens, credentials, or URLs to integrate SAP BTP, Kyma runtime with external systems.
    14  You can find all the provisioning steps in the [provisioning](../../cmd/broker/provisioning.go) file.
    15  
    16  > **NOTE:** The timeout for processing this operation is set to `24h`.
    17  
    18  ## Deprovision
    19  
    20  Each deprovisioning step is responsible for a separate part of cleaning Kyma runtime dependencies. To properly deprovision all the dependencies, you need the data used during the Kyma runtime provisioning. The first step finds the previous operation and copies the data.
    21  
    22  None of the deprovisioning steps should block the entire deprovisioning operation. Use the `RetryOperationWithoutFail` function from the `DeprovisionOperationManager` struct to skip a step in case of a retry timeout. Set a 5-minute, at the most, timeout for retries in a step.
    23  Only one step may fail the operation, namely `Check_Runtime_Removal`. It fails the operation in case of a timeout while checking for the Provisioner to remove the shoot. 
    24  Once the step is successfully executed, it isn't retried (every deprovisioning step is defined in a separate stage). If a step has been skipped due to a retry timeout or error, the [Cron Job](../contributor/06-50-deprovision-retrigger-cronjob.md) tries to deprovision all remaining Kyma runtime dependencies again at a scheduled time.
    25  You can find all the deprovisioning steps in the [deprovisioning](../../cmd/broker/deprovisioning.go) file.
    26  
    27  > **NOTE:** The timeout for processing this operation is set to `24h`.
    28  
    29  ## Update
    30  
    31  The update process is triggered by an [OSB API update operation](https://github.com/openservicebrokerapi/servicebroker/blob/master/spec.md#updating-a-service-instance) request.
    32  You can find all the updating steps in the [update](../../cmd/broker/update.go) file.
    33  
    34  ## Upgrade cluster
    35  
    36  The upgrade cluster process is triggered by upgrade cluster orchestration.
    37  You can find all the upgrading cluster steps in the [upgrade_cluster](../../cmd/broker/upgrade_cluster.go) file.
    38  
    39  ## Upgrade Kyma
    40  
    41  The upgrade Kyma process is triggered by upgrade Kyma orchestration.
    42  You can find all the upgrading Kyma steps in the [upgrade_kyma](../../cmd/broker/upgrade_kyma.go) file.
    43  
    44  ## Provide additional steps
    45  
    46  You can configure SAP BTP, Kyma runtime operations by providing additional steps. To add a new step, follow these tutorials:
    47  
    48  <div tabs name="runtime-provisioning-deprovisioning" group="runtime-provisioning-deprovisioning">
    49    <details>
    50    <summary label="provisioning">
    51    Provisioning
    52    </summary>
    53  
    54  1. Create a new file in [this directory](../../internal/process/provisioning).
    55  
    56  2. Implement the following interface in your provisioning or deprovisioning step:
    57  
    58      ```go
    59      type Step interface {
    60          Name() string
    61          Run(operation internal.Operation, logger logrus.FieldLogger) (internal.Operation, time.Duration, error)
    62      }
    63      ```
    64  
    65     - `Name()` method returns the name of the step that is used in logs.
    66     - `Run()` method implements the functionality of the step. The method receives operations as an argument to which it can add appropriate overrides or save other used variables.
    67  
    68  
    69      ```go
    70      operation.InputCreator.SetOverrides(COMPONENT_NAME, []*gqlschema.ConfigEntryInput{
    71          {
    72              Key:   "path.to.key",
    73              Value: SOME_VALUE,
    74          },
    75          {
    76              Key:    "path.to.secret",
    77              Value:  SOME_VALUE,
    78              Secret: ptr.Bool(true),
    79          },
    80      })
    81      ```
    82  
    83      If your functionality contains long-term processes, you can store data in the storage.
    84      To do this, add the following field to the provisioning operation in which you want to save data:
    85  
    86      ```go
    87      type Operation struct {
    88  
    89          // These fields are serialized to JSON and stored in the storage
    90          RuntimeVersion RuntimeVersionData `json:"runtime_version"`
    91  
    92          // These fields are not stored in the storage
    93          InputCreator ProvisionerInputCreator `json:"-"`
    94      }
    95      ```
    96  
    97      By saving data in the storage, you can check if you already have the necessary data and avoid time-consuming processes. You must always return the modified operation from the method.
    98  
    99      See the example of the step implementation:
   100  
   101      ```go
   102      package provisioning
   103  
   104      import (
   105          "encoding/json"
   106          "net/http"
   107          "time"
   108  
   109          "github.com/kyma-incubator/compass/components/provisioner/pkg/gqlschema"
   110          "github.com/kyma-incubator/compass/components/kyma-environment-broker/internal"
   111          "github.com/kyma-incubator/compass/components/kyma-environment-broker/internal/storage"
   112  
   113          "github.com/sirupsen/logrus"
   114      )
   115  
   116      type HelloWorldStep struct {
   117          operationStorage storage.Operations
   118          client           *http.Client
   119      }
   120  
   121      type ExternalBodyResponse struct {
   122          data  string
   123          token string
   124      }
   125  
   126      func NewHelloWorldStep(operationStorage storage.Operations, client *http.Client) *HelloWorldStep {
   127          return &HelloWorldStep{
   128              operationStorage: operationStorage,
   129              client:           client,
   130          }
   131      }
   132  
   133      func (s *HelloWorldStep) Name() string {
   134          return "Hello_World"
   135      }
   136  
   137      // Your step can be repeated in case any other step fails, even if your step has already done its job
   138      func (s *HelloWorldStep) Run(operation internal.Operation, log *logrus.Entry) (internal.Operation, time.Duration, error) {
   139          log.Info("Start step")
   140  
   141          // Check whether your step should be run or if its job has been done in the previous iteration
   142          // All non-save operation data are empty (e.g. InputCreator overrides)
   143  
   144          // Add your logic here
   145  
   146          // Add a call to an external service (optional)
   147          response, err := s.client.Get("http://example.com")
   148          if err != nil {
   149              // Error during a call to an external service may be temporary so you should return time.Duration
   150              // All steps will be repeated in X seconds/minutes
   151              return operation, 1 * time.Second, nil
   152          }
   153          defer response.Body.Close()
   154  
   155          body := ExternalBodyResponse{}
   156          err = json.NewDecoder(response.Body).Decode(&body)
   157          if err != nil {
   158              log.Errorf("error: %s", err)
   159              // Handle a process failure by returning an error or time.Duration
   160          }
   161  
   162          // If a call or any other action is time-consuming, you can save the result in the operation
   163          // If you need an extra field in the Operation structure, add it first
   164          // In the following step, you can check beforehand if a given value already exists in the operation
   165          operation.HelloWorlds = body.data
   166          updatedOperation, err := s.operationStorage.UpdateOperation(operation)
   167          if err != nil {
   168              log.Errorf("error: %s", err)
   169              // Handle a process failure by returning an error or time.Duration
   170          }
   171  
   172          // If your step finishes with data which should be added to override used during the Runtime provisioning,
   173          // add an extra value to operation.InputCreator, then return the updated version of the Application
   174          updatedOperation.InputCreator.SetOverrides("component-name", []*gqlschema.ConfigEntryInput{
   175              {
   176                  Key:   "some.key",
   177                  Value: body.token,
   178              },
   179          })
   180  
   181          // Return the updated version of the Application
   182          return *updatedOperation, 0, nil
   183      }
   184      ```
   185  
   186  3. Add the step to the [`/cmd/broker/provisioning.go`](../../cmd/broker/provisioning.go) file:
   187  
   188      ```go
   189      provisioningSteps := []struct {
   190     		stage   string
   191     		step     provisioning.Step
   192     	}{
   193     		{
   194     			stage: "create_runtime",
   195     			step:   provisioning.NewHelloWorldStep(db.Operations(), &http.Client{}),
   196     		},
   197      }
   198      ```
   199  
   200     Once all the steps in the stage have run successfully, the stage is  not retried even if the application is restarted.
   201  
   202    </details>
   203  
   204    <details>
   205    <summary label="upgrade">
   206    Upgrade
   207    </summary>
   208  
   209  1. Create a new file in [this directory](../../internal/process/upgrade_kyma).
   210  
   211  2. Implement the following interface in your upgrade step:
   212  
   213      ```go
   214      type Step interface {
   215          Name() string
   216          Run(operation internal.UpgradeOperation, logger logrus.FieldLogger) (internal.UpgradeOperation, time.Duration, error)
   217      }
   218      ```
   219  
   220     - `Name()` method returns the name of the step that is used in logs.
   221     - `Run()` method implements the functionality of the step. The method receives operations as an argument to which it can add appropriate overrides or save other used variables.
   222  
   223  
   224      If your functionality contains long-term processes, you can store data in the storage.
   225      To do this, add this field to the upgrade operation in which you want to save data:
   226  
   227      ```go
   228      type UpgradeOperation struct {
   229          Operation `json:"-"`
   230  
   231          // add additional data here
   232      }
   233      ```
   234  
   235      By saving data in the storage, you can check if you already have the necessary data and avoid time-consuming processes. You should always return the modified operation from the method.
   236  
   237      See the example of the step implementation:
   238  
   239      ```go
   240      package upgrade
   241  
   242      import (
   243          "encoding/json"
   244          "net/http"
   245          "time"
   246  
   247          "github.com/kyma-incubator/compass/components/provisioner/pkg/gqlschema"
   248          "github.com/kyma-incubator/compass/components/kyma-environment-broker/internal"
   249          "github.com/kyma-incubator/compass/components/kyma-environment-broker/internal/storage"
   250  
   251          "github.com/sirupsen/logrus"
   252      )
   253  
   254      type HelloWorldStep struct {
   255          operationStorage storage.Operations
   256          client           *http.Client
   257      }
   258  
   259      type ExternalBodyResponse struct {
   260          data  string
   261          token string
   262      }
   263  
   264      func NewHelloWorldStep(operationStorage storage.Operations, client *http.Client) *HelloWorldStep {
   265          return &HelloWorldStep{
   266              operationStorage: operationStorage,
   267              client:           client,
   268          }
   269      }
   270  
   271      func (s *HelloWorldStep) Name() string {
   272          return "Hello_World"
   273      }
   274  
   275      // Your step can be repeated in case any other step fails, even if your step has already done its job
   276      func (s *HelloWorldStep) Run(operation internal.UpgradeOperation, log *logrus.Entry) (internal.UpgradeOperation, time.Duration, error) {
   277          log.Info("Start step")
   278  
   279          // Check whether your step should be run or if its job has been done in the previous iteration
   280          // All non-save operation data are empty (e.g. InputCreator overrides)
   281  
   282          // Add your logic here
   283  
   284          // Add a call to an external service (optional)
   285          response, err := s.client.Get("http://example.com")
   286          if err != nil {
   287              // Error during a call to an external service may be temporary so you should return time.Duration
   288              // All steps will be repeated in X seconds/minutes
   289              return operation, 1 * time.Second, nil
   290          }
   291          defer response.Body.Close()
   292  
   293          body := ExternalBodyResponse{}
   294          err = json.NewDecoder(response.Body).Decode(&body)
   295          if err != nil {
   296              log.Errorf("error: %s", err)
   297              // Handle a process failure by returning an error or time.Duration
   298          }
   299  
   300          // If a call or any other action is time-consuming, you can save the result in the operation
   301          // If you need an extra field in the UpgradeOperation structure, add it first
   302          // in the step below; beforehand, you can check if a given value already exists in the operation
   303          operation.HelloWorlds = body.data
   304          updatedOperation, err := s.operationStorage.UpdateUpgradeOperation(operation)
   305          if err != nil {
   306              log.Errorf("error: %s", err)
   307              // Handle a process failure by returning an error or time.Duration
   308          }
   309  
   310          // If your step finishes with data which should be added to override used during the Runtime upgrade,
   311          // add an extra value to operation.InputCreator, then return the updated version of the Application
   312          updatedOperation.InputCreator.SetOverrides("component-name", []*gqlschema.ConfigEntryInput{
   313              {
   314                  Key:   "some.key",
   315                  Value: body.token,
   316              },
   317          })
   318  
   319          // Return the updated version of the Application
   320          return *updatedOperation, 0, nil
   321      }
   322      ```
   323  
   324  3. Add the step to the [`/cmd/broker/upgrade_cluster.go`](../../cmd/broker/upgrade_cluster.go) or [`/cmd/broker/upgrade_kyma.go`](../../cmd/broker/upgrade_kyma.go) file:
   325  
   326      ```go
   327      upgradeSteps := []struct {
   328     		weight   int
   329     		step     upgrade_kyma.Step
   330     	}{
   331     		{
   332     			weight: 1,
   333     			step:   upgrade_kyma.NewHelloWorldStep(db.Operations(), &http.Client{}),
   334     		},
   335      }
   336      ```
   337  
   338     </details>
   339  </div>
   340  
   341  ## Stages
   342  
   343  An operation defines stages and steps which represent the work you must do. A stage is a grouping unit for steps. A step is a part of a stage. An operation can consist of multiple stages, and a stage can consist of multiple steps. You group steps in a stage when you have some sensitive data which you don't want to store in database. In such a case you temporarily store the sensitive data in the memory and go through the steps. Once all the steps in a stage are successfully executed, the stage is marked as finished and never repeated again, even if the next one fails. If any steps fail at a given stage, the whole stage is repeated from the beginning.