github.com/oam-dev/kubevela@v1.9.11/design/vela-core/cloud-resource-data-passing.md (about)

     1  # Data Passing From Cloud Resource
     2  
     3  ## Introduction
     4  
     5  This proposal is to explain how to pass data from cloud resource to other workloads.
     6  
     7  ## Background
     8  
     9  In the issue [#4339](https://github.com/kubevela/kubevela/issues/4339), we have discussed how to pass data from cloud
    10  resource to other workloads. Here's the summary of the discussion.
    11  
    12  ### Why
    13  
    14  KubeVela leverages Terraform controller to provision cloud resource within Kubernetes environment.
    15  In cases where cloud databases are involved, it is necessary to pass along connection information to the related
    16  workloads. This information Secret is created by terraform controller and stored in Kubernetes Secrets.
    17  
    18  ### Goals
    19  
    20  To pass data from cloud resource, there are two perspectives: method and workload location
    21  
    22  **Workload Location**
    23  
    24  1. Local cluster
    25  2. Managed cluster
    26  
    27  **Method**
    28  
    29  1. Pass Secret: Secret Object is created at destination cluster. Workload refer to the Secret name and key.
    30  2. Pass Value: Secret Object is **NOT** created at destination cluster. KubeVela fill the workload spec directly with
    31     connection information value.
    32  
    33  ## Proposal
    34  
    35  There are four combinations of workload location and method. The implementation state is list below. We will discuss
    36  each of them separately.
    37  
    38  |            | Local | Managed Cluster |
    39  |-------------|-------|----------------|
    40  | Pass Secret | ✅     | ✅            |
    41  | Pass Value  | ✅     |               |
    42  
    43  ### Workload in local cluster
    44  
    45  #### Pass Secret
    46  
    47  This combination is the most straightforward one. The Secret Object is already created at local cluster when
    48  Configuration (cloud resource) is available. Workload can simply refer to the Secret name in Application spec.
    49  
    50  ```yaml
    51  apiVersion: core.oam.dev/v1beta1
    52  kind: Application
    53  metadata:
    54    name: local-pass-secret
    55  spec:
    56    components:
    57      - name: db
    58        type: alibaba-rds
    59        properties:
    60          instance_name: favorite-links
    61          database_name: links
    62          account_name: oamtest
    63          password: U34rfwefwefffaked
    64          writeConnectionSecretToRef:
    65            name: db-conn
    66      - name: favorite-links
    67        type: webservice
    68        dependsOn:
    69          - db
    70        properties:
    71          image: oamdev/nodejs-mysql-links:v0.0.1
    72          port: 4000
    73        traits:
    74          - type: service-binding
    75            properties:
    76              envMappings:
    77                DATABASE_HOST:
    78                  secret: db-conn
    79                  key: DB_PUBLIC_HOST
    80                DATABASE_NAME:
    81                  secret: db-conn
    82                  key: DATABASE_NAME
    83                DATABASE_USER:
    84                  secret: db-conn
    85                  key: DB_USER
    86                DATABASE_PASSWORD:
    87                  secret: db-conn
    88                  key: DB_PASSWORD
    89  ```
    90  
    91  #### Pass Value
    92  
    93  This combination is similar to the previous one. The difference is that we have to read the Secret Object values in
    94  workflow. Then utilize component level input/output mechanism to pass value to workload.
    95  
    96  **Note**: `apply-component` can pass value from workflow level output to component level input. It only works for local
    97  cluster. So we can make use of it to pass value to workload. In the [_Pass Value_ + _Maneged
    98  cluster_](#workload-in-managed-cluster) section, you'll see why it won't work in multi-cluster scenario.
    99  
   100  ```yaml
   101  apiVersion: core.oam.dev/v1beta1
   102  kind: Application
   103  metadata:
   104    name: local-pass-value
   105  spec:
   106    components:
   107      - name: sample-db
   108        type: alibaba-rds
   109        properties:
   110          instance_name: sample-db
   111          account_name: oamtest
   112          password: U34rfwefwefffaked
   113          writeConnectionSecretToRef:
   114            name: db-conn
   115      # Example from https://kubevela.io/docs/end-user/components/cloud-services/provision-and-consume-database
   116      - name: receiver
   117        type: webservice
   118        properties:
   119          image: zzxwill/flask-web-application:v0.3.1-crossplane
   120          port: 80
   121          env:
   122            - name: endpoint
   123            - name: DB_PASSWORD # keep the style to suit image
   124            - name: username
   125        inputs:
   126          - from: host
   127            parameterKey: env[0].value
   128          - from: password
   129            parameterKey: env[1].value
   130          - from: username
   131            parameterKey: env[2].value
   132  
   133    workflow:
   134      steps:
   135        - name: apply-db
   136          type: apply-component
   137          properties:
   138            component: sample-db
   139        - name: read-secret
   140          type: read-secret
   141          properties:
   142            name: db-conn
   143          outputs:
   144            - name: host
   145              valueFrom: output.value.DB_PUBLIC_HOST
   146            - name: username
   147              valueFrom: output.value.DB_USER
   148            - name: password
   149              valueFrom: output.value.DB_PASSWORD
   150        - name: apply-receiver
   151          type: apply-component
   152          properties:
   153            component: receiver
   154  ```
   155  
   156  ### Workload in managed cluster
   157  
   158  For workload in managed cluster, passing secret can be implemented. But we are facing some issues to pass value.
   159  
   160  ![pass-value](../resources/cloud-resource-pass-value.png)
   161  
   162  As displayed in mind map above, the main problem to **pass value** is reading data from either Configuration or Secret
   163  it created. Here is an image that tells relationship between Application, Configuration and Secret, which helps to
   164  understand 2.1 and 2.2.1
   165  
   166  ![mechanism](../resources/cloud-resource-mechanism.png)
   167  
   168  #### Pass Secret
   169  
   170  Here's a demo about passing secret from cloud resource component to other worload. In this demo application will first
   171  create a database and then create two workloads in different clusters. The both workloads will use the same DB.
   172  
   173  ```yaml
   174  apiVersion: core.oam.dev/v1beta1
   175  kind: Application
   176  metadata:
   177    name: multi-cluster-app-with-db
   178  spec:
   179    components:
   180      - name: db
   181        type: alibaba-rds
   182        properties:
   183          instance_name: favorite-links
   184          database_name: links
   185          account_name: oamtest
   186          password: U34rfwefwefffaked
   187          writeConnectionSecretToRef:
   188            name: db-conn
   189      - name: favorite-links
   190        type: webservice
   191        properties:
   192          image: oamdev/nodejs-mysql-links:v0.0.1
   193          port: 4000
   194        traits:
   195          - type: service-binding
   196            properties:
   197              envMappings:
   198                DATABASE_HOST:
   199                  secret: db-conn
   200                  key: DB_PUBLIC_HOST
   201                DATABASE_NAME:
   202                  secret: db-conn
   203                  key: DATABASE_NAME
   204                DATABASE_USER:
   205                  secret: db-conn
   206                  key: DB_USER
   207                DATABASE_PASSWORD:
   208                  secret: db-conn
   209                  key: DB_PASSWORD
   210    policies:
   211      - name: worker
   212        type: topology
   213        properties:
   214          clusters:
   215            - cluster-worker
   216      - name: all-cluster
   217        type: topology
   218        properties:
   219          clusters:
   220            - cluster-worker
   221            - local
   222      - name: links-comp
   223        type: override
   224        properties:
   225          selector:
   226            - favorite-links
   227    workflow:
   228      steps:
   229        - name: create-rds
   230          type: apply-component
   231          properties:
   232            component: db
   233        - name: read-secret
   234          type: read-object
   235          properties:
   236            apiVersion: v1
   237            kind: Secret
   238            name: db-conn
   239          outputs:
   240            - name: db-host
   241              valueFrom: |
   242                import "encoding/base64"
   243                base64.Decode(null, output.value.data.DB_PUBLIC_HOST)
   244            - name: db-user
   245              valueFrom: |
   246                import "encoding/base64"
   247                base64.Decode(null, output.value.data.DB_USER)
   248            - name: db-password
   249              valueFrom: |
   250                import "encoding/base64"
   251                base64.Decode(null, output.value.data.DB_PASSWORD)
   252            - name: db-name
   253              valueFrom: |
   254                import "encoding/base64"
   255                base64.Decode(null, output.value.data.DATABASE_NAME)
   256        - name: export-secret
   257          type: export-data
   258          properties:
   259            name: db-conn
   260            namespace: default
   261            kind: Secret
   262            topology: worker
   263          inputs:
   264            - from: db-host
   265              parameterKey: data.DB_PUBLIC_HOST
   266            - from: db-user
   267              parameterKey: data.DB_USER
   268            - from: db-password
   269              parameterKey: data.DB_PASSWORD
   270            - from: db-name
   271              parameterKey: data.DATABASE_NAME
   272  
   273        - name: deploy-web
   274          type: deploy
   275          properties:
   276            policies: [ "all-cluster", "links-comp" ]
   277  ```
   278  
   279  #### Discuss About Passing Value
   280  
   281  There is still some scenarios we need to pass value to sub-cluster workload. For example: the helm chart is
   282  off-the-shelf and can't be modified
   283  like [wordpress](https://github.com/helm/charts/blob/master/stable/wordpress/values.yaml). It requires to pass the
   284  database endpoint to values of chart. In this case, we can't pass a secret to it.
   285  
   286  To fill the last grid of table, we have to solve either 2.1 or 2.2.
   287  
   288  - To solve 2.1 we need to refactor the Configuration rendering logic and unify it to CUE.
   289  - To solve 2.2, 2.2.3 is an easier way and need less effort.
   290  
   291  Before we put in effort to solve this problem, we need to collect more requirements to see if it's necessary.
   292  
   293  ##### Apply-component and Deploy
   294  
   295  Here's another discussion about why *apply-component* can't work for workload in managed cluster. In [Pass Value +
   296  Local cluster](#workload-in-local-cluster) combination, we use `read-object` and `apply-component` to overcome the
   297  problem that Secret
   298  value can be read in `workflow` but not in `component` of Application.
   299  
   300  Now switching to multi cluster scenario, `apply-component` is not working because it is designed before KubeVela has
   301  multi-cluster capability. After KubeVela have multi-cluster capability, we have `deploy` workflow-step to dispatching
   302  component to multi-cluster.
   303  
   304  Unlike `apply-componnet` which has built-in capability to convert workflow-level input/output to component-level ones.
   305  `deploy` can accept input/output, but they will be applied to workflow properties itself like most other
   306  workflow-steps. In another word you can change this part:
   307  
   308  ```cue
   309   parameter: {
   310       //+usage=If set to false, the workflow will suspend automatically before this step, default to be true.
   311       auto: *true | bool
   312       //+usage=Declare the policies that used for this deployment. If not specified, the components will be deployed to the hub cluster.
   313       policies: *[] | [...string]
   314       //+usage=Maximum number of concurrent delivered components.
   315       parallelism: *5 | int
   316       //+usage=If set false, this step will apply the components with the terraform workload.
   317       ignoreTerraformComponent: *true | bool
   318   }
   319  ```
   320  
   321  ### Conclusion
   322  
   323  For cloud resource data passing scenarios, we have solutions for three out of four scenarios. The last one still needs
   324  some discussion and is waiting for more requirements.
   325