Framework Spec
OpenFABR CDF defines a configuration language for package authors to describe how they define reusable cloud infrastructure, in the form of package metadata which consist of a number of files.
It is worth pointing that the package metadata files are mandatory when a package is integrated into a GUI-based tool such as FABR Infra because those software tooling can only rely on machine readable information to assist project creators to build cloud infrastructure using a specific package. It is however optional, though highly recommended when using a package directly with CDF, as long as the same information is documented by package authors. it is therefore package authors' responsibility to maintain up-to-date documentations for packages they develop.
Types and Constraints
OpenFABR CDF as a specification needs types and constraints to set up the foundation for the value system, just like other programming languages such as SQL.
Types
PLAIN_TEXT
- a plain text string value, UTF-8 encoded, usually less than 2,000 characters in length
NUMBER
- a numerical value
BOOLEAN
- a boolean (true/false) value
TEXT_LIST
- a list of
SIMPLE_TEXT
values, UTF-8 encoded, usually less than 100 entries NUM_LIST
- a list of
NUMBER
values URL
- a valid URL type string value, UTF-8 encoded, under 2048 characters long
SIMPLE_TEXT
- a URL-friendly string value, usually less than 100 characters in length and commonly used in forming domain names and/or URLs, UTF-8 encoded
MARKDOWN_TEXT
- a Markdown-formatted string value, usually for descriptive purposes, UTF-8 encoded, CommonMark spec, less than 2,000 characters in length IP_ADDRESS: in either IPv4 or IPv6 format
Constraints
REQUIRED
- can apply to all types
UNIQUE
- value must be unique among the same type of
Construct
in aStack
, also implying REQUIRED IN_LIST(TEXT_LIST)
- for
TEXT
type IN_LIST(NUMBER_LIST)
- for
NUMBER
type MIN_LENGTH(NUMBER)
- for
TEXT
andSLUG
types MAX_LENGTH(NUMBER)
- for
TEXT
andSLUG
types DEPENDENT_ON(MAP<TEXT, Any>)
- for all types
Construct Types
Constructs
(see definitions below) are the building blocks of an infrastructure architecture (defined as an InfraPlan
below). Each construct must be one of the following types:
General
- not directly infrastructure related, it defines necessary metadata about the package itself.
Network
- the foundational network environment an application runs in. e.g. AWS VPC
Service
- a deployable target where your application code runs, typically containerised app runtime and ephemeral. A
Service
can communicate with otherService
instances andComponents
. Services can be internal/private or public Internet facing. They can be hooked up to CI/CD pipelines so that application code release can be automated, such as a NodeJS REST API on an AWS ECS Fargate service. Component
- third-party infrastructure services that your application depends on. They are typically private/internal and persistent. They could be self-hosted by you or managed services by a cloud provider e.g. AWS Aurora Database, AWS SQS, or AWS Elasticache for Redis
Relations
- indicates a directional link between a service or component and another service or component, for a specific purpose. E.g. NodeJS API communicating with an Aurora Database instance.
Custom
- where local customisation is packaged, which is almost always needed to complement the use of the other building blocks from a given implementation package.
Aspect
- another way to apply local customisation, albeit targeting a specific resource provisioned in the underlying cloud vendor.
Below are the framework-defined attributes for each construct.
More can be defined by package authors per package and package authors are encouraged to do so to expose configurable options for project creators to fine-tune underlying infrastructure.
General
Name: SIMPLE_TEXT
See GeneralConfig
interface defined in CDF
Network
Name: SIMPLE_TEXT
Cidr: complex type [subnet: IP_ADDRESS, mask: NUMBER]
See NetworkConfig
interface defined in CDF
Component (and Trait)
Name: SIMPLE_TEXT
UsageType: SIMPLE_TEXT | IN_LIST (all supported component types such as storage, messaging, and streaming)
Type: SIMPLE_TEXT
Subtype: SIMPLE_TEXT
See TraitConfig
and ComponentConfig
interfaces defined in CDF
Service (and Runtime)
Name: SIMPLE_TEXT
PackageType: SIMPLE_TEXT | IN_LIST (‘container’, ‘application’)
Type: SIMPLE_TEXT
Subtype: SIMPLE_TEXT
See RuntimeConfig
and ServiceConfig
interfaces defined in CDF
Relation
Start: SIMPLE_TEXT | IN_LIST (all Service & Component names defined in the same Plan)
Finish: SIMPLE_TEXT | IN_LIST (all Service & Component names defined in the same Plan)
Bidirectional: BOOLEAN
See RelationConfig
interface defined in CDF
Custom
This is a unique building block.
It is meant to be implemented locally, specific to the belonging Plan;
It has several inputs defined by the implementation package, usually an aggregation of all the underlying cloud services managed by those building blocks;
With those inputs, further customisations are expected to be packaged in a Custom module;
There can be as many Custom modules as needed.
See Custom
abstract class defined in CDF
Aspect
TBD
Package Metadata
The package metadata consist a pack of files covering all that has been mentioned above. It’s intended to be used by software tooling to understand the abstraction that a package makes available for project creators to use. The primary goal is making it a machine readable protocol so that software tooling can be developed to further aid project creators when using a selected package.
An example of the files is shown below,
Those files are described individually below.
Package Manifest
It is aptly named cdf.manifest.json
inside a package at root level, which contains attributes listed below to describe the package and links to other metadata files. It is the top-level plan when defining a package for consumption.
An example (as defined in PackageManifest
interface defined in CDF) is shown below,
/**
* Interface for modelling a package manifest json file that provides information about the package.
* Crucially it also carries two references respectively to a) a json schema file for validating json config files and b) a template file for custom code blocks.
*
* @group For both project creators and package authors
*/
export interface PackageManifest extends OptionalIconAware {
/**
* The descriptive name of the package.
*/
name?: string;
/**
* The unique identifier of the package.
*/
identifier: string;
/**
* The author of the package.
*/
vendor: string;
/**
* The SPDX license identifier for the license that the package is released under.
*
* @see https://spdx.org/licenses/
*/
license: string;
/**
* The description of the package.
*/
description?: string;
/**
* Information about the support provided for the package.
*/
support?: SupportInfo;
/**
* The version of OpenFABR CDF that this package is compatible with, following semantic versioning.
*/
cdf: string;
/**
* Information about tooling the package relies on.
*/
tooling: ToolingInfo;
/**
* Information about constructs defined in the package.
*/
constructs: ConstructsInfo;
}
A sample cdf.manifest.json
file is shown below,
{
"identifier": "fabr-cdktf-gcp",
"vendor": "FABR",
"license": "UNLICENSED",
"cdf": "1.x",
"name": "A test package built by CDKTF for AWS",
"description": "This package is for testing only",
"support": {
"email": "hello@abc.com",
"phone": "0800123456789"
},
"tooling": {
"command": "cdktf deploy",
"runtime": "cdktf",
"language": "typescript"
},
"constructs": {
"schema": "schema.json",
"network": {
"icon": "https://abc.com/network.png"
},
"components": {
"types": {
"hello": { "type": "chinese", "subtype": "mandarin", "icon": "https://abc.com/hello.png", "description": "Hello Component" },
"fizz": { "type": "city", "subtype": "hong-kong" }
}
},
"services": {
"types": {
"world": { "type": "solar-system", "subtype": "earth", "deployment": "NASA would help" },
"buzz": { "type": "country", "subtype": "morocco", "deployment": "Fly over", "icon": "https://abc.com/morocco.png", "description": "Well done in World Cup" }
}
},
"relations": {
"types": {
"hello": "world",
"fizz": "buzz"
}
},
"custom": {
"icon": "https://abc.com/code.png",
"template": "template.ts"
}
}
}
The exact file name cdf.manifest.json
has to be used in order to be located by any software tooling.
Within constructs
field defined as ConstructsInfo
interface in CDF, it carries important typing information for Components, Services and Relations, among other metadata.
Types and Subtypes in Components
For a package, all available Component typings (expressed as Type + Subtype with a unique name) are expected to be listed here.
See ComponentsInfo
interface defined in CDF
Types and Subtypes in Services
For a package, all available Service typings (expressed as Type + Subtype with a unique name) are expected to be listed here.
See ServicesInfo
interface defined in CDF
Pairings between Components and Services in Relations
For a package, all available Relations (expressed as a pair between a Service/Component and another Service/Component, both of which are expressed as a unique name mentioned above for Component and Service typings) are expected to be listed here.
See RelationsInfo
interface defined in CDF
Misc.
Each different type of Components, Services and Relations is encouraged to carry its own icon and description. Same goes for Network and Custom constructs.
See NetworkInfo
and CustomInfo
interfaces defined in CDF
Config Definition via JSON Schema
It is a JSON schema file, usually generated with the help of cdf-cli
tool from reading the TypeScript based package configurations. It is not expected to be manually edited afterwards. Whenever there is a change to the package configurations, the schema file should be re-generated.
The name of the config definition can be arbitrary as long as it is referenced correctly by the package manifest, i.e. cdf.manifest.json
.
Template for Custom Code Block
It is IaC runtime and language specific, i.e. if the package is created for Terraform CDF TypeScript, then the template is expected to be in TypeScript. Below is an example,
import { err, Result } from "neverthrow";
import * as cdf from "@openfabr/cdf";
import { PackageCustomModule, PackageInfraConfig, PackageInfraPlanConstructs } from "./package-config";
export class ProjectCustomModule implements PackageCustomModule {
enhanceWith(config: PackageInfraConfig, result: cdf.InfraPlan<PackageInfraPlanConstructs>, scope: any): Result<cdf.InfraPlanOutputs, cdf.PlanError> {
// Write your customisation here and remove the line below.
return err({ message: "Method not implemented." });
}
}
The name of the template can be arbitrary as long as it is referenced correctly by the Package Manifest
file.