Specification

Resources

Provisioner

Endpoint


backend-openapi.yaml (view on GitHub) :

---
openapi: 3.0.2
info:
  title: Order Service API
  version: 0.1.0
  description: Simple Order Service API
  contact:
    name: Laurent Broudoux
    url: https://github.com/lbroudoux
    email: laurent@microcks.io
  license:
    name: MIT License
    url: https://opensource.org/licenses/MIT
paths:
  /orders:
    post:
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderInfo'
            examples:
              valid_order:
                value:
                  customerId: lbroudoux
                  productQuantities:
                  - productName: Millefeuille
                    quantity: 1
                  - productName: Eclair Cafe
                    quantity: 2
                  totalPrice: 9.4
              invalid_order:
                value:
                  customerId: lbroudoux
                  productQuantities:
                  - productName: Millefeuille
                    quantity: 1
                  - productName: Eclair Chocolat
                    quantity: 1
                  totalPrice: 4.8
      responses:
        "201":
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderInfo'
              examples:
                valid_order:
                  value:
                    id: 5455c8e8-087a-426e-8440-65c8c005d871
                    status: CREATED
                    customerId: lbroudoux
                    productQuantities:
                    - productName: Millefeuille
                      quantity: 1
                    - productName: Eclair Cafe
                      quantity: 2
                    totalPrice: 9.4
          description: Order is correct and has been created
        "422":
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnavailableProduct'
              examples:
                invalid_order:
                  value:
                    productName: Eclair Chocolat
                    details: Eclair Chocolat are not available at the moment
          description: "Order cannot be processed because of a validation error (ex:\
            \ unavailable product)"
      operationId: PlaceOrder
      summary: Place a new Order
      description: Place a new Order in the system. Will perform extra checks before
        saving Order to detect invalid demand
components:
  schemas:
    OrderInfo:
      description: Represents info needed for creating an Order
      required:
      - customerId
      - productQuantities
      - totalPrice
      type: object
      properties:
        customerId:
          description: Identifier of customer of this order
          type: string
        productQuantities:
          description: Desired products and quantities for this order
          type: array
          items:
            $ref: '#/components/schemas/ProductQuantity'
        totalPrice:
          format: double
          description: Total price of the order
          type: number
    ProductQuantity:
      description: Association of product name with quantity
      required:
      - productName
      - quantity
      type: object
      properties:
        productName:
          description: Desired product name
          type: string
        quantity:
          description: Desired quantity
          type: integer
    Order:
      description: Full created Order with all informations
      type: object
      allOf:
      - required:
        - id
        - status
        type: object
        properties:
          id:
            description: Unique identifier of order
            type: string
          status:
            description: Status of Order
            enum:
            - CREATED
            - VALIDATED
            - CANCELED
            - FAILED
            type: string
      - $ref: '#/components/schemas/OrderInfo'
    UnavailableProduct:
      description: ""
      required:
      - productName
      type: object
      properties:
        productName:
          description: ""
          type: string
        details:
          description: Details of unavailability
          type: string

score.yaml (view on GitHub) :

apiVersion: score.dev/v1b1
metadata:
  name: frontend
containers:
  frontend:
    image: busybox
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo Hello $SERVICE_DEP!; sleep 5; done"]
    variables:
      SERVICE_DEP: ${resources.backend.url}/0.1.0/orders
service:
  ports:
    tcp:
      port: 8080
      targetPort: 80
resources:
  backend:
    type: endpoint
    params:
      port: 8181
      openapi_file: ./backend-openapi.yaml
      openapi_title: Order Service API


10-endpoint-with-microcks.provisioners.yaml (view on GitHub) :

- uri: template://custom-provisioners/endpoint-with-microcks
  type: endpoint
  description: Outputs an endpoint URL for connecting to an other workload (a Microcks mock is generated if not found).
  init: |
    hostname: {{ splitList "." .Id | last }}
    {{ $parsedPath := .Params.openapi_file | splitList "/" }}
    {{ if eq (len $parsedPath) 0 }}
    resourcesPath: "."
    {{ else }}
    resourcesPath: {{ trimSuffix (last $parsedPath) .Params.openapi_file | trimSuffix "/" }}
    {{ end }}    
  supported_params:
    - port
    - openapi_file
    - openapi_title
  outputs: |
    {{ $w := (index .WorkloadServices .Init.hostname) }}
    {{ if or (not $w) (not $w.ServiceName) }}
    url: http://localhost:9090/rest/{{ .Params.openapi_title | replace " " "+" }}
    {{ else }}
    url: http://{{ .Init.hostname }}:{{ .Params.port }}
    {{ end }}    
  expected_outputs:
    - url
  services: |
    {{ $w := (index .WorkloadServices .Init.hostname) }}
    {{ if or (not $w) (not $w.ServiceName) }}
    {{ .Init.hostname }}-mock:
      image: quay.io/microcks/microcks-cli:latest
      restart: always
      entrypoint:
        - "microcks-cli"
        - "import"
        - "{{ .Params.openapi_file }}:true"
        - "--microcksURL=http://microcks:8080/api"
        - "--insecure"
        - "--keycloakClientId=foo"
        - "--keycloakClientSecret=bar"
      cap_drop:
        - ALL
      read_only: true
      user: "65532"
      volumes:
      - type: bind
        source: {{ .Init.resourcesPath }}
        target: /resources
        read_only: true
      depends_on:
        microcks:
          condition: service_started
          required: true
    {{ end }}    

Initialize your local workspace, by importing a specific community provisioner:

score-commpose init --provisioners REPLACE-ME-WITH-ACTUAL-PROVISIONER-FILE-URL.yaml

Note: you need to replace REPLACE-ME-WITH-ACTUAL-PROVISIONER-FILE-URL.yaml by the actual provisioner file you want to use and import. More information here.

Get the provisioners definition:

score-compose provisioners list

Generate the platform specific manifests:

score-commpose generate score.yaml

See the resource outputs:

score-commpose resources list

You can run the following command on each resource listed with the previous command to get their outputs:

score-commpose resources get-outputs

Deploy the generated manifests:

docker compose up -d

See the running containers:

docker ps


10-endpoint-with-microcks-cli.provisioners.yaml (view on GitHub) :

- uri: cmd://bash#endpoint-with-microcks-cli
  type: endpoint
  description: Outputs an endpoint URL for connecting to an other workload (a Microcks mock is generated if not found).
  supported_params:
    - port
    - openapi_file
  expected_outputs:
    - url
  args:
  - -c
  - |
    STDIN=$(cat)
    PARAM_PORT=$(echo $STDIN | yq eval -p json '.resource_params.port')
    PARAM_OPENAPI_FILE=$(echo $STDIN | yq eval -p json '.resource_params.openapi_file')
    WORKLOAD=$(echo $STDIN | yq eval -p json '.resource_id | split(".") | .[-1]')
    WORKLOAD_EXISTS=$(echo $STDIN | WORKLOAD=${WORKLOAD} yq eval -p json '.workload_services | has(strenv(WORKLOAD))')
    URL_HOSTNAME=${WORKLOAD}:${PARAM_PORT}
    URL_SCHEME="http"
    URL_PATH=""
    if [ "$WORKLOAD_EXISTS" != "true" ]; then
      URL_HOSTNAME="microcks.127.0.0.1.nip.io"
      URL_SCHEME="https"
      SPEC_FILE="${PARAM_OPENAPI_FILE}"
      URL_PATH=/rest/$(cat $SPEC_FILE | yq eval '.info.title' | yq '. |= sub(" ", "+")')
      set -eu -o pipefail
      microcks-cli import ${SPEC_FILE}:true --microcksURL=https://${URL_HOSTNAME}/api --insecure --keycloakClientId=foo --keycloakClientSecret=bar >&2
    fi
    OUTPUTS='{"resource_outputs":{"url":"%s://%s%s"},"manifests":[]}'
    printf "$OUTPUTS" "$URL_SCHEME" "$URL_HOSTNAME" "$URL_PATH"    

README.md (view on GitHub) :

Prerequisites:
- Have `yq` installed to load resource's params.
- Have `microcks` CLI installed to import the API service into Microcks.

Initialize your local workspace, by importing a specific community provisioner:

score-k8s init --provisioners REPLACE-ME-WITH-ACTUAL-PROVISIONER-FILE-URL.yaml

Note: you need to replace REPLACE-ME-WITH-ACTUAL-PROVISIONER-FILE-URL.yaml by the actual provisioner file you want to use and import. More information here.

Get the provisioners definition:

score-k8s provisioners list

Generate the platform specific manifests:

score-k8s generate score.yaml

See the resource outputs:

score-k8s resources list

You can run the following command on each resource listed with the previous command to get their outputs:

score-k8s resources get-outputs

Deploy the generated manifests:

kubectl apply -f manifests.yaml

See the running containers:

kubectl get all