Skip to content
This repository has been archived by the owner on Feb 5, 2021. It is now read-only.

Latest commit

 

History

History
1061 lines (963 loc) · 32.9 KB

cellery-syntax.md

File metadata and controls

1061 lines (963 loc) · 32.9 KB

Cellery Language Syntax

This section focuses on the Cellery syntax and explain how to compose cells.

The Cellery Language is a subset of Ballerina and Ballerina extensions. Therefore the language syntax of Cellery resembles with normal Ballerina language syntax.

This README explains,

Cell

A Cell is a collection of components, APIs, Ingresses and Policies. A Cell record is initialized as follows; Components can be added to the components map in the CellImage record.

cellery:CellImage helloCell = {
   components: {
       helloComp:helloWorldComp
   }
};

Composite

A composite is a cut down version of cells. A composite doesn't have a network boundary. A gateway is not getting attached to a composite and therefore a composite components support only following ingress types.

  1. TCP Ingress
  2. GRPC Ingress
  3. HttpPort Ingress

Components matching above criteria can be added to the components map in the Composite record.

cellery:Composite helloComposite = {
   components: {
       helloComp:helloWorldComp
   }
};

Component

A component represents an implementation of the business logic (in a docker image or a legacy system) and a collections of network accessible entry points (Ingresses) and parameters. A sample component with inline definitions would be as follows:

cellery:Component helloComponent = {
    name: "hello-api",
    src: {
        image: "docker.io/wso2cellery/samples-hello-world-api" // source docker image
    },
    ingresses: {
        helloApi: <cellery:HttpApiIngress>{ 
            port: 9090,
            context: "hello",
            definition: {
                resources: [
                    {
                        path: "/",
                        method: "GET"
                    }
                ]
            },
            expose: "global"
        }
    },
    envVars: {
        MESSAGE: { value: "hello" }
    }
};

Ingresses

An Ingress represents an entry point into a cell component. An ingress can be an HTTP, TCP, GRPC or Web endpoint.

1. HTTP Ingress

HttpApiIngress supports defining HTTP API as an entry point for a cell. API definitions can be provided inline or as a swagger file. A sample HttpApiIngress instance with inline API definition would be as follows:

cellery:HttpApiIngress helloAPI = {
    port: 9090,
    context: "hello",
    apiVersion: "1.0.0",
    definition: {
        resources: [
            {
                path: "/",
                method: "GET"
            }
        ]
    },
    expose: "global"
};

A sample HttpApiIngress record with swagger 2.0 definition can be defined as follows. The definitions are resolved at the build time. Therefore the build method is implemented to parse swagger file, and assign to ingress.

cellery:HttpApiIngress employeeIngress = {
    port: 8080,
    context: "employee",
    expose: "local"
};

public function build(cellery:ImageName iName) returns error? {
    cellery:HttpApiIngress helloAPI = {
        port: 9090,
        context: "hello",
        apiVersion: "1.0.0",
        definition: <cellery:ApiDefinition>cellery:readSwaggerFile("./resources/employee.swagger.json"),
        expose: "global"
    };
    ...
}
Expose

A particular HttpApiIngress can be exposed as an API by setting expose field. This field accepts two values.

-  `local`: Expose an HTTP API via local cell gateway.
-  `global`: Expose an HTTP API via global gateway.

By setting expose to global, the API will be published to the global gateway ready to receive external traffic. In this case, the cell name and the context provided in the ingress is combined to create the full context for the global API.

cellery:HttpApiIngress helloAPI = {
    port: 9090,
    context: "hello",
    apiVersion: "1.0.0",
    // ...
    expose: "global"
};

In the above ingress exposed as global, the API will he published with the context /<cell-name>/hello/1.0.0.

In addition, user can expose the ingresses of a particular cell to outside with a common root context by using the globalPublisher configuration.

cellery:HttpApiIngress helloAPI = {
    context: "hello",
    apiVersion: "1.0.0",
    // ...
    expose: "global"
};

cellery:CellImage hrCell = {
    globalPublisher: {
        apiVersion: "1.0.1",
        context: "myorg"
    },
};

Here, http ingresses marked as expose: "global" will be published to the global API gateway. The context of the each published API will be the concatenation of context defined in globalPublisher and the sub context defined in each ingress.

Therefore, the global API will be published as /myorg/hello/1.0.1. Note that the root context /myorg is picked from the globalPublisher section and the sub context hello is picked from the http ingress. The version is specified in globalPublisher section.

2. Web Ingress

Web cell ingress allows web traffic to the cell. A sample Web ingress would be as following: Web ingress are always exposed globally.

cellery:WebIngress webIngress = { 
    port: 8080,
    gatewayConfig: {
        vhost: "abc.com",
        context: "/demo" //default to “/”
    }
};
2.1 Define TLS for Web Ingress

TLS can be defined to a web ingress as below:

// Web Component
cellery:Component webComponent = {
    name: "web-ui",
    src: {
        image: "wso2cellery/samples-hello-world-webapp"
    },
    ingresses: { 
        webUI: <cellery:WebIngress>{ // Ingress is defined in line in the ingresses map.
            port: 80,
            gatewayConfig: {
                vhost: "hello.com",
                tls: {
                    key: "",
                    cert: ""
                }
            }
        }
    }
};
// Create the cell image with cell web component.
cellery:CellImage webCell = {
      components: {
          webComp: webComponent
      }
  };

Values for tls key and tls cert can be assigned at the run method as below.

public function run(cellery:ImageName iName, map<cellery:ImageName> instances, boolean startDependencies, boolean shareDependencies) returns (cellery:InstanceState[] | error?) {
    //Read TLS key file path from ENV and get the value
    string tlsKey = readFile(config:getAsString("tls.key"));
    string tlsCert = readFile(config:getAsString("tls.cert"));

    //Assign values to cell->component->ingress
    cellery:CellImage webCell = check cellery:constructCellImage(iName);
    cellery:WebIngress webUI = <cellery:WebIngress>webCell.components["webComp"]["ingresses"]["webUI"];
    webUI["gatewayConfig"]["tls"]["key"] = tlsKey;
    webUI["gatewayConfig"]["tls"]["cert"] = tlsCert;
    // Create the cell instance
    return <@untainted> cellery:createInstance(webCell, iName);
}

// Read the file given in filePath and return the content as a string.
function readFile(string filePath) returns (string) {
    io:ReadableByteChannel bchannel = io:openReadableFile(filePath);
    io:ReadableCharacterChannel cChannel = new io:ReadableCharacterChannel(bchannel, "UTF-8");

    var readOutput = cChannel.read(2000);
    if (readOutput is string) {
        return readOutput;
    } else {
        error err = error("Unable to read file " + filePath);
        panic err;
    }
}
2.2 Authenticate Web Ingress

Web ingress support Open ID connect. OIDC config can be defined as below.

cellery:Component portalComponent = {
    name: "portal",
    src: {
        image: "wso2cellery/samples-pet-store-portal"
    },
    ingresses: {
        portal: <cellery:WebIngress>{ // Web ingress will be always exposed globally.
            port: 80,
            gatewayConfig: {
                vhost: "pet-store.com",
                context: "/",
                oidc: {
                    nonSecurePaths: ["/", "/app/*"],
                    providerUrl: "",
                    clientId: "",
                    clientSecret: "",
                    redirectUrl: "http://pet-store.com/_auth/callback",
                    baseUrl: "http://pet-store.com/",
                    subjectClaim: "given_name"
                }
            }
        }
    }
};

If dynamic client registration is used dcr configs can be provided as below in the clientSecret field.

    ingresses: {
        portal: <cellery:WebIngress>{
            port: 80,
            gatewayConfig: {
                vhost: "pet-store.com",
                context: "/portal",
                oidc: {
                    nonSecurePaths: ["/portal"], // Default [], optional field
                    providerUrl: "https://idp.cellery-system/oauth2/token",
                    clientId: "petstoreapplicationcelleryizza",
                    clientSecret: {
                        dcrUser: "admin",
                        dcrPassword: "admin"
                    },
                    redirectUrl: "http://pet-store.com/_auth/callback",
                    baseUrl: "http://pet-store.com/items/",
                    subjectClaim: "given_name"
                }
            }
        }
    },

Similar to above sample the clientSecret and clientId values be set at the run method to pass value at the run time without burning to the image.

3. TCP Ingress

TCP ingress supports defining TCP endpoints. A sample TCP ingress would be as following:

cellery:TCPIngress tcpIngress = {
    backendPort: 3306,
    gatewayPort: 31406
};

The backendPort is the actual container port which is exposed by the container. The gatewayPort is the port exposed by the cell gateway.

4. GRPC Ingress

GRPC ingress supports defining GRPC endpoints. This is similar to TCP ingress with optional field to define protofile. protofile field is resolved at build method since protofile is packed at build time.

cellery:GRPCIngress grpcIngress = {
    backendPort: 3306,
    gatewayPort: 31406
};

public function build(cellery:ImageName iName) returns error? {                                                                    
    grpcIngress.protoFile = "./resources/employee.proto";
    ...
}
5. HttpPort Ingress

HttpPort ingress supports defining a http port as an endpoint. This ingress is used to declare endpoint in composite components.

//Stock Component
cellery:Component stockComponent = {
    name: "stock",
    src: {
        image: "wso2cellery/sampleapp-stock:0.3.0"
    },
    ingresses: {
        http:<cellery:HttpsPortIngress>{port: 8080}
    }
};

cellery:Composite stockComposite = {
    components: {
        stockComp: stockComponent
    }
};

EnvVars

A cell developer can require a set of environment parameters that should be passed to a Cell instance for it to be properly functional.

// Employee Component
cellery:Component employeeComponent = {
    name: "employee",
    src: {
        image: "docker.io/celleryio/sampleapp-employee"
    },
    ingresses: {
        employee: <cellery:HttpApiIngress>{
            port: 8080,
            context: "employee",
            expose: "local"
        }
    },
    envVars: {
        SALARY_HOST: { value: "" }
    },
    labels: {
        team: "HR"
    }
};

Note the parameters SALARY_HOST in the Cell definition above. This parameters can be set in the run time of this Cell.

public function run(cellery:ImageName iName, map<cellery:ImageName> instances, boolean startDependencies, boolean shareDependencies) returns (cellery:InstanceState[] | error?) {
    employeeCell.components.empComp.envVars.SALARY_HOST.value = config:getAsString("salary.host");
    return <@untainted> cellery:createInstance(employeeCell, iName);
}
Getting Host and Port from a component

Sometimes you may need to pass one component's host and port as an environment variable to another component for intra-cell communication. For this, you can use cellery:getHost(<component>) and cellery:getPort(<component>) functions.

    cellery:Component myComponent = {
        name: "comp1",
        ...
        envVars: {
            COMP2_ADDRESS: {
                value: cellery:getHost(comp2) + ":" + cellery:getPort(comp2)
            },
        },
        ...
    };

Resources

Cellery allows to specify how much CPU and memory (RAM) each component needs. Resources can be specified as requests and limits. When component have resource requests specified, the scheduler can make better decisions about which nodes to place component on. When component have their limits specified, contention for resources on a node can be handled in a specified manner.

Following is sample syntax on how to define limits/requests.

import celleryio/cellery;

public function build(cellery:ImageName iName) returns error? {
    //Stock Component
    cellery:Component stockComponent = {
        name: "stock",
        src: {
            image: "wso2cellery/sampleapp-stock:0.3.0"
        },
        ingresses: {
            stock: <cellery:HttpApiIngress>{ port: 8080,
                context: "stock",
                definition: {
                    resources: [
                        {
                            path: "/options",
                            method: "GET"
                        }
                    ]
                },
                expose: "local"
            }
        },
        resources: {
            requests: {
                memory: "64Mi",
                cpu: "250m"
            },
            limits: {
                memory: "128Mi",
                cpu: "500m"
            }
        }
    };

    cellery:CellImage stockCell = {
        components: {
            stockComp: stockComponent
        }
    };
    return <@untainted> cellery:createImage(stockCell, iName);
}

Scaling

1. Auto-Scaling

Autoscale policies can be specified by the Cell developer at Cell creation time.

If a component has a scaling policy as the AutoScalingPolicy then component will be scaled with horizontal pod autoscaler.

import ballerina/io;
import celleryio/cellery;

public function build(cellery:ImageName iName) returns error? {
    //Pet Component
    cellery:Component petComponent = {
        name: "pet-service",
        src: {
            image: "docker.io/isurulucky/pet-service"
        },
        ingresses: {
            stock: <cellery:HttpApiIngress>{ port: 9090,
                context: "petsvc",
                definition: {
                    resources: [
                        {
                            path: "/*",
                            method: "GET"
                        }
                    ]
                }
            }
        },
        scalingPolicy: <cellery:AutoScalingPolicy> {
            minReplicas: 1,
            maxReplicas: 10,
            metrics: {
                cpu: <cellery:Value>{ threshold : "500m" },
                memory: <cellery:Percentage> { threshold : 50 }
            }
        }

    };

    cellery:CellImage petCell = {
        components: {
            petComp: petComponent
        }
    };
    return <@untainted> cellery:createImage(petCell, iName);
}

The Auto-scale policy defined by the developer can be overridden at the runtime by providing a different policy at the runtime.

2. Zero-scaling

Zero scaling is powered by Knative. The zero-scaling have minimum replica count 0, and hence when the component did not get any request, the component will be terminated and it will be running back once a request was directed to the component.

A zero-scaling policy can be defined as below.

import ballerina/io;
import celleryio/cellery;

public function build(cellery:ImageName iName) returns error? {
    //Pet Component
    cellery:Component petComponent = {
        name: "pet-service",
        src: {
            image: "docker.io/isurulucky/pet-service"
        },
        ingresses: {
            stock: <cellery:HttpApiIngress>{ port: 9090,
                context: "petsvc",
                definition: {
                    resources: [
                        {
                            path: "/*",
                            method: "GET"
                        }
                    ]
                }
            }
        },
        scalingPolicy: <cellery:ZeroScalingPolicy> {
                maxReplicas: 10,
                concurrencyTarget: 25
        }

    };

    cellery:CellImage petCell = {
        components: {
            petComp: petComponent
        }
    };
    return <@untainted> cellery:createImage(petCell, iName);
}

Probes

Liveness and readiness probes can be defined for a component. The probes can be defined by the means of tcp socket, command or as a http-get.

1. TCP Socket
import celleryio/cellery;
public function build(cellery:ImageName iName) returns error? {
    int salaryContainerPort = 8080;

    // Salary Component
    cellery:Component salaryComponent = {
        name: "salary",
        src: {
            image: "docker.io/celleryio/sampleapp-salary"
        },
        ingresses: {
            SalaryAPI: <cellery:HttpApiIngress>{
                port:salaryContainerPort,
                context: "payroll",
                definition: {
                    resources: [
                        {
                            path: "salary",
                            method: "GET"
                        }
                    ]
                },
                expose: "global"
            }
        },
        probes: {
            liveness: {
                initialDelaySeconds: 30,
                kind: <cellery:TcpSocket>{
                    port:salaryContainerPort
                }
            }
        }
    };
}
2. Command
import celleryio/cellery;
public function build(cellery:ImageName iName) returns error? {
    int salaryContainerPort = 8080;

    // Salary Component
    cellery:Component salaryComponent = {
        name: "salary",
        src: {
            image: "docker.io/celleryio/sampleapp-salary"
        },
        ingresses: {
            SalaryAPI: <cellery:HttpApiIngress>{
                port:salaryContainerPort,
                context: "payroll",
                definition: {
                    resources: [
                        {
                            path: "salary",
                            method: "GET"
                        }
                    ]
                },
                expose: "global"
            }
        },
        probes: {
            readiness: {
                initialDelaySeconds: 10,
                timeoutSeconds: 50,
                kind: <cellery:Exec>{
                    commands: ["bash", "-version"]
                }
            }
        }
    };
}
3. HTTP-GET
import celleryio/cellery;
public function build(cellery:ImageName iName) returns error? {
    int salaryContainerPort = 8080;

    // Salary Component
    cellery:Component salaryComponent = {
        name: "salary",
        src: {
            image: "docker.io/celleryio/sampleapp-salary"
        },
        ingresses: {
            SalaryAPI: <cellery:HttpApiIngress>{
                port:salaryContainerPort,
                context: "payroll",
                definition: {
                    resources: [
                        {
                            path: "salary",
                            method: "GET"
                        }
                    ]
                },
                expose: "global"
            }
        },
        probes: {
            readiness: {
                initialDelaySeconds: 10,
                timeoutSeconds: 50,
                kind: <cellery:HttpGet>{
                    port: salaryContainerPort,
                    path: "/healthz"
                }
            }
        }
    };
}

Volumes

Volumes can be mounted to a component. Cellery support mounting 3 types of volumes to a component.

1. Configuration

Configurations allow to decouple configuration artifacts from image content to keep containerized applications portable. Configurations can be add to component as following.

    cellery:Component helloComponent = {
        name: "hello-api",
        src: {
            image: "docker.io/wso2cellery/samples-hello-world-api-hello-service"
        },
        ingresses: {
            helloApi: <cellery:HttpApiIngress>{ port: 9090,
                context: "hello",
                authenticate: false,
                apiVersion: "v1.0.0",
                definition: {
                    resources: [
                        {
                            path: "/",
                            method: "GET"
                        }
                    ]
                },
                expose: "global"
            }
        },
        volumes: {
            // Mounting a non existing configuration.
            // Configuration will be created and mounted to component
            config: {
                path: "/tmp/config",
                readOnly: false,
                volume:<cellery:NonSharedConfiguration>{
                    name:"my-config",
                    data:{
                        debug:"enable",
                        logs:"enable"
                    }
                }
            },
            // Mounting an existing configuration.
            // Configuration is already available in runtime and will be mounted to the component.
            configShared: {
                path: "/tmp/shared/config",
                readOnly: false,
                volume:<cellery:SharedConfiguration>{
                    name:"my-config-shared"
                }
            }
        }
    };
2. Secrets

Secret recors let you store and manage sensitive information, such as passwords, OAuth tokens, and ssh keys. Secret can be add to component as following.

    cellery:Component helloComponent = {
        name: "hello-api",
        src: {
            image: "docker.io/wso2cellery/samples-hello-world-api-hello-service"
        },
        ingresses: {
            helloApi: <cellery:HttpApiIngress>{ port: 9090,
                context: "hello",
                authenticate: false,
                apiVersion: "v1.0.0",
                definition: {
                    resources: [
                        {
                            path: "/",
                            method: "GET"
                        }
                    ]
                },
                expose: "global"
            }
        },
        volumes: {
            // Mounting a non existing secret.
            // Secret will be created and mounted to component
            secret: {
                path: "/tmp/secret/",
                readOnly: false,
                volume:<cellery:NonSharedSecret>{
                    name:cellery:generateVolumeName("my-secret"),
                    data:{
                        username:"admin",
                        password:"admin"
                    }
                }
            },
            // Mounting an existing secret.
            // Secret is already available in runtime and will be mounted to the component.
            secertShared: {
                path: "/tmp/shared/secret",
                readOnly: false,
                volume:<cellery:SharedSecret>{
                    name:"my-secret-shared"
                }
            }
        }
    };
3. Volume Claims

Volume Claims (or PVCs) are objects that request storage resources from your cluster. They’re similar to a voucher that your deployment can redeem for storage access. Volume Claims can be add to component as following.

    cellery:Component helloComponent = {
        name: "hello-api",
        src: {
            image: "docker.io/wso2cellery/samples-hello-world-api-hello-service"
        },
        ingresses: {
            helloApi: <cellery:HttpApiIngress>{ port: 9090,
                context: "hello",
                authenticate: false,
                apiVersion: "v1.0.0",
                definition: {
                    resources: [
                        {
                            path: "/",
                            method: "GET"
                        }
                    ]
                },
                expose: "global"
            }
        },
        volumes: {
            // Mounting a non existing volume claim.
            // Volume claim will be created and mounted to component 
            volumeClaim: {
                path: "/tmp/pvc/",
                readOnly: false,
                volume:<cellery:K8sNonSharedPersistence>{
                    name:"pv1",
                    mode:"Filesystem",
                    storageClass:"slow",
                    accessMode: ["ReadWriteMany"],
                    request:"2G",
                     lookup: {
                        labels: {
                            release: "stable"
                        },
                        expressions: [{ key: "environment", operator: "In", values: ["dev", "staging"]}]
                     }
                }
            },
            // Mounting an existing volume claim.
            // Volume claim is already available in runtime and will be mounted to the component.
            volumeClaimShared: {
                path: "/tmp/pvc/shared",
                readOnly: true,
                volume:<cellery:K8sSharedPersistence>{
                    name:"pv2"
                }
            }
        }
    };

Intra Cell Communication

Cell components can communicate with each other. This is achieved via environment variables. Two components can be linked via environment variables in the run method. For an example, consider the scenario below. The employee component expects SALARY_HOST, which is the hostname of salary component.

Employee component:

import ballerina/io;
import celleryio/cellery;

public function build(cellery:ImageName iName) returns error? {
    int salaryContainerPort = 8080;

    // Salary Component
    cellery:Component salaryComponent = {
        name: "salary",
        src: {
            image: "docker.io/celleryio/sampleapp-salary"
        },
        ingresses: {
            SalaryAPI: <cellery:HttpApiIngress>{
                port:salaryContainerPort,
                context: "payroll",
                definition: {
                    resources: [
                        {
                            path: "salary",
                            method: "GET"
                        }
                    ]
                },
                expose: "local"
            }
        },
        labels: {
            team: "Finance",
            owner: "Alice"
        }
    };

    // Employee Component
    cellery:Component employeeComponent = {
        name: "employee",
        src: {
            image: "docker.io/celleryio/sampleapp-employee"
        },
        ingresses: {
            employee: <cellery:HttpApiIngress>{
                port: 8080,
                context: "employee",
                expose: "local",
                definition: <cellery:ApiDefinition>cellery:readSwaggerFile("./resources/employee.swagger.json")
            }
        },
        envVars: {
            SALARY_HOST: {
                value: cellery:getHost(salaryComponent)
            },
            PORT: {
                value: salaryContainerPort
            }
        },
        labels: {
            team: "HR"
        }
    };

    cellery:CellImage employeeCell = {
        components: {
            empComp: employeeComponent,
            salaryComp: salaryComponent
        }
    };

    return <@untainted> cellery:createImage(employeeCell, iName);
}

The envVar SALARY_HOST value is provided at the build time as shown above, which enables the employee component to communicate with the salary component.

Inter Cell Communication

In addition to components within a cell, Cells themselves can communicate with each other. This is also achieved via envVars. Two cells can be linked via envVar in the run method.

When a Cell Image is built it will generate a reference file describing the APIs/Ports that are exposed by itself. This cell reference will be available locally, either when you build or pull the image. This reference can be imported in another Cell definition which is depending on the former, and can be used to link the two Cells at the runtime.

Consider following cell definition:

import ballerina/io;
import celleryio/cellery;

public function build(cellery:ImageName iName) returns error? {
    //Build Stock Cell
    io:println("Building Stock Cell ...");
    //Stock Component
    cellery:Component stockComponent = {
        name: "stock",
        src: {
            image: "docker.io/celleryio/sampleapp-stock"
        },
        ingresses: {
            stock: <cellery:HttpApiIngress>{ port: 8080,
                context: "stock",
                definition: {
                    resources: [
                        {
                            path: "/options",
                            method: "GET"
                        }
                    ]
                },
                expose: "local"
            }
        }
    };
    cellery:CellImage stockCell = {
        components: {
            stockComp: stockComponent
        }
    };
    return <@untainted> cellery:createImage(stockCell, iName);
}

Generated reference file for above cell definition is as follows:

{
  "stock_api_url":"http://{{instance_name}}--gateway-service:80/stock"
}

If a cell component wants to access the stock api, it can be done as below:

public function build(cellery:ImageName iName) returns error? {
    //HR component
    cellery:Component hrComponent = {
        name: "hr",
        src: {
            image: "docker.io/celleryio/sampleapp-hr"
        },
        ingresses: {
            "hr": <cellery:HttpApiIngress>{
                port: 8080,
                context: "hr-api",
                definition: {
                    resources: [
                        {
                            path: "/",
                            method: "GET"
                        }
                    ]
                },
                expose: "global"
            }
        },
        dependencies: {
            cells: {
                stockCellDep: <cellery:ImageName>{ org: "myorg", name: "stock", ver: "1.0.0" } // dependency as a struct
            }
        }
    };

    hrComponent["envVars"] = {
        stock_api_url: { value: <string>cellery:getReference(hrComponent, "stockCellDep")["stock_api_url"] }
    };

    // Cell Initialization
    cellery:CellImage hrCell = {
        components: {
            hrComp: hrComponent
        }
    };
    return <@untainted> cellery:createImage(hrCell, iName);
}

public function run(cellery:ImageName iName, map<cellery:ImageName> instances, boolean startDependencies, boolean shareDependencies) returns (cellery:InstanceState[] | error?) {
    cellery:CellImage hrCell = check cellery:constructCellImage(iName);
    return <@untainted> cellery:createInstance(hrCell, iName, instances);
}

The hrComponent depends on the stockCell that is defined earlier. The dependency information are specified as a component attribute.

    dependencies: {
        cells: {
            stockCellDep: <cellery:ImageName>{ org: "myorg", name: "stock", ver: "1.0.0" } // dependency as a struct
        }
    }

cellery:getReference(hrComponent, "stockCellDep").stock_api_url method reads the json file and set value with place holder.

Note the run method above, which takes a variable argument map for the references of the dependency cells. These are names of already deployed cell instances, which will be used to resolve the urls and link with this cell instance. As an example, if the stock cell instance name is stock-app then the stockRef.stock_api_url returns the host name of the running stock cell instance as http://stock-app--gateway-service:80/stock.

What's Next?

  • Developing a Cell - step by step explanation on how you could define your own cells.
  • Samples - a collection of useful samples.