spec icon indicating copy to clipboard operation
spec copied to clipboard

Proposal - Parameter references

Open dhiguero opened this issue 2 years ago • 3 comments

Hi all! Following the conversations from the last community call, this issue is a proposal to introduce a mechanism to be able to reference items of the application structure from the component parametrization section.

Motivation

Up to this point, setting parameters on an application requires the user to fill the collection of key:value pairs that will be applied when the actual application is being "instanciated" by the runtime. While this approach works from the point of view of a user for simple cases, it introduces a problem when trying to create tooling around the usage of applications. For example, consider use cases where users want to deploy several instances of the same application.

To illustrate the current state and the proposed changes, consider a simple application with two components where "publicapi" requires a parameter to be able to connect to the "database" one. The current approach is to create a parameter and set that parameter manually as in the following example:

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: two-component-app
...
spec:
  components:
    - name: publicapi
      type: internal-api
      properties: # properties targeting component parameters.
        debug: "false"
        dbhost: "database" # dbhost will be used internally to build the database connection string
    - name: database
      type: mysql # assume a mysql component as database

While this approach works for some use cases, it could be improved to improve the usability of the Application entity as describe in the following paragraphs.

Proposal

The proposal is to introduce a method by which a parameter can reference a value of the Application entity. Given the current spec, the initial proposal is to use special syntax to distinguish between referencing parameters and literal ones. Taken inspiration from the component parameter definition section, it could look like:

    - name: publicapi
      type: internal-api
      properties: # properties targeting component parameters.
        debug: "false"
        dbhost: valueRef.spec.components[1].name # use the name attribute the database component

In this case, if a parameter starts with valueRef the runtime understands that this value needs to interpreted instead of being a literal one. To improve usability further, we could also propose other syntax such as the following one, where the name of the component is used to easily identify the target component.

    - name: publicapi
      type: internal-api
      properties: # properties targeting component parameters.
        debug: "false"
        dbhost: valueRef.spec.components["database"].name # use the name attribute the database component

Benefits

This proposal is an enabler of future improvements around OAM, its runtimes, and the tools around it. To highlight some of the main benefits:

  • Facilitate parametrization from tools: From the point of view of creating tools around OAM, introducing a method to be able to understand that a parameter references another element of the application will simplify its design increasing their capabilities. In this way, it would be possible to parse an application entity and determine upfront that it contain errors without the need of deploying it. Without it, there is not enough context to determine if a parameter value is a reference to other component or just a literal value.
  • Creating instances: Some use cases will benefit from future improvements around being able to deploy several instances of an application. To do that, having a robust parameter system where services names can be distinguished from standard parameters will help simplifying the future design.
  • Reducing parametrization: In applications where multiple components require a specific parameter (e.g., database, configuration option, etc), this approach will allow setting just one of those parameters and referencing it from the other components. By following this approach, we can also reduce the errors in cases where the user mistypes some parameter in one of the components.

What do you think?

dhiguero avatar Mar 22 '22 16:03 dhiguero

Hi @dhiguero , thanks for the proposal, we already implemented this feature in KubeVela by using X-Definition, let me introduce briefly.

When we using an application and want to ref the component name in the component, this field is automatically injected by the system. So, there's no need to declare it in the properties.

In the ComponentDefinition, we can use context.name to indicate the component name for properties render.

apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
  name: stateless
spec:
  schematic:
    cue:
      template: |
        output: {
        	apiVersion: "apps/v1"
        	kind:       "Deployment"
        	spec: template: spec: containers: [{
        		name:  context.name
        		image: parameters.image
        	}]
        }
        parameters: image: string

So in the application, we don't need to specify anything, it can be used like below:

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: website
spec:
  components:
    - name: hello
      type: stateless
      properties:
        image: crccheck/hello-world

The deployment rendered out will have the component name automatically.

More information in the context that can be used:

https://kubevela.net/docs/platform-engineers/components/custom-component#full-available-information-in-cue-context

wonderflow avatar Mar 24 '22 03:03 wonderflow

Hi @wonderflow, thanks for your answer. I switched from an Spec perspective to a Kubevela one, and found that using component dependencies with input and output match the use case I was trying to solve with this proposal, which was referencing the name of a component in the application entity.

This is an example taken from the current documentation of Kubevela about how to reference one component from another. I leave a copy for reference here.

Referencing MySQL from Worpress
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: wordpress-with-mysql
  namespace: default
spec:
  components:
    - name: mysql
      type: helm
      outputs:
        # the output is the mysql service address
        - name: mysql-svc
          valueFrom: output.metadata.name + ".default.svc.cluster.local"
      properties:
        repoType: helm
        url: https://charts.bitnami.com/bitnami
        chart: mysql
        version: "8.8.2"
        values:
          auth:
            rootPassword: mypassword
    - name: wordpress
      type: helm
      inputs:
        # set the host to mysql service address
        - from: mysql-svc
          parameterKey: properties.values.externalDatabase.host
      properties:
        repoType: helm
        url: https://charts.bitnami.com/bitnami
        chart: wordpress
        version: "12.0.3"
        values:
          mariadb:
            enabled: false
          externalDatabase:
            user: root
            password: mypassword
            database: mysql
            port: 3306

The main issue I see with this approach is that it is Kubevela based, but it is not directly supported by the Spec. I think we should think about introducing the input/output section in the Application entity in OAM 4, which is currently not supported, and potentially compare it with other alternatives such as the one in this proposal.

dhiguero avatar Apr 06 '22 10:04 dhiguero

@dhiguero Yes, we can introduce that into the OAM spec. Let's go ahead for that.

wonderflow avatar Apr 12 '22 14:04 wonderflow