Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rfc: Cloud Assembly Specification #1119

Closed
wants to merge 18 commits into from
Closed

Conversation

RomainMuller
Copy link
Contributor

@RomainMuller RomainMuller commented Nov 8, 2018

Looking forward to supporting a more integrated deployment experience
with support of multiple stacks (with deployment order constraints
honored) as well as assets, this proposes a specification for a
Cloud Assembly that determines a document storage format.

Fixes: #956


TODO:

  • Specify the deployment behavior (order resolution, ability to parallelize, ...)
  • Improve the phrasing around missing information
  • Add TypeScript definition for the manifest document (must be possible to generate JSON Schema from it)
  • Add language around Drop providers publishing a JSON schema that allows for easy validation
  • Describe how deployment systems should proceed
  • Flesh out the "full assembly" example
  • Describe digital signature algorithm
  • Refine the digital signature validation procedure & requirements

Looking forward to supporting a more integrated deployment experience
with support of multiple stacks (with deployment order constraints
honored) as well as assets, this proposes a specification for a
*Cloud Assembly* that determines a document storage format.

Fixes: #956
@RomainMuller RomainMuller force-pushed the rmuller/cloud-assembly branch from 3bec2b0 to a43db28 Compare November 8, 2018 15:45
@RomainMuller RomainMuller added the help wanted We are asking the community to submit a PR to resolve this issue. label Nov 8, 2018
specifications/cloud_assembly.md Outdated Show resolved Hide resolved
including all the parts that are needed in order to deploy those to *the cloud*. This document exposes the specification
of the *Cloud Assembly* format as well as requirements imposed on *Cloud Assemblers* and *Cloud Runtimes*.

### Goals
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should be "tenets" (or "design goals"). To write good tenets, a nice trick I've learned is to think (and even describe) what it is NOT. The purpose of tenets is to help make design decisions. Each tenet should describe a dimension or continuum and state which side of the continuum we are going to prefer.

Also, there's a bit of conflation here between goals for the spec it self (e.g. "cloud agnostic", there's no goal for assemblies to be cloud agnostic) and the assembly (e.g. "extensible", there isn't a goal for the spec to be extensible).

Anyway - this needs a bit more work, happy to spend some face to face time on this if you like

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well I very much would like the specification to be fundamentally cloud-agnostic, which is why I use "the cloud" and not "AWS". As for extensibility, this may not be the right term indeed (settled for this now until I figure out a better one).


Documents in the archive can be stored with any name and directory structure, however the following entries at the root
of the archive are reserved for special use:
* `manifest.json` **MUST** be present and contains the [manifest document](#manifest-document) for the *Cloud Assembly*.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe index.json? Give it a bit of a "web standard" ora

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"If it's a cat, call it a cat".

The [JSON] specification allows for keys to be specified multiple times in a given `object`. However, *Cloud Assembly*
consumers **MAY** assume keys are unique, and [*Cloud Assemblers*](#cloud-assemblers) **SHOULD** avoid generating
duplicate keys. If duplicate keys are present, the latest specified value **SHOULD** be preferred.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should include a JSON schema and/or a typescript type definition (preferably the former generated from the latter)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, that was always the plan :P

specifications/cloud_assembly.md Outdated Show resolved Hide resolved

Each [`Drop` Type](#drop-type) can produce outputs that can be used in order to allow other `Drop`s to consume the
resources they procude. Each `Drop` implementer is responsible to document the output attributes it supports. References
to these outputs are modeled using special `string` tokens within entries of the `properties` section of `Drop`s:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spec is missing a section on how to publish new drop types. Specifically, it should include a JSON schema which allows tools to validate the manifest "properties" section against

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a part of it but I reckon there might be more to it than just this. It'll be pretty inefficient to discuss over GitHub issues, though. Let's talk about this & report the outcome back here.

specifications/cloud_assembly.md Outdated Show resolved Hide resolved
specifications/cloud_assembly.md Show resolved Hide resolved
Deployment systems **MUST** support at least one protocol, and **SHOULD** support all the protocols specified in
the following sub-sections.

##### The `npm` protocol
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks nice, but I am wondering if it's at all possible to implement a deployment tool that can interact with drop types from multiple languages.

Perhaps the drop type provider is not a class but rather a POSIX program and the protocol between the deployment tool and the provider is based on STDIN/STDOUT/ARGV/ENV.... They will be discovered by a PATH look-up (and will include some version handshake). Might be a much more powerful model.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I was thinking but I wanted to talk about it before writing it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both of these are tying declaration to implementation.

More generically, how about just an identifier string? (Could be namespaced a la com.amazonaws.cloudformationstack or something)

In that case, we can even build tools to statically analyze the drops, without necessarily executing them. In direct opposition is the following:

{
   "type": "bash -c '$(which foobar)/../libexec/bin/cfnprovider'"
}

How is any tool going to analyze all the CloudFormation stacks in an Assembly if this is the format of "identifier" they may have to contend with?

A compromise might be found in the following:

{
  "type": "com.amazonaws.cloudformation.stack",
  "executionHint": "cdk-cloudformation-stack"
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value of the URI style string is that the protocol string allows you to specify a mechanism for accessing (e.g: npm:// means you would need node to be available & get the support by running npm install <packageName>). Then the path segment would give info about the package coordinates, and then how to use it. Implementations would support certain protocols and know how to execute. So no bash -c blah here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I was responding to Elad's suggestion of using subprocesses here.

  2. Even if we were to use npm:// coordinates, does the identifier have meaning without the NPM package that contains code to interpret it? To have any hope of tools that interpret the model apart from simply executing it, it must.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree with Rico. Why limit ourselves to a string, when we have the full power of JSON available? I think the Drop Type being an object is more powerful (and easier to extend in the future).

specifications/cloud_assembly.md Outdated Show resolved Hide resolved
specifications/cloud_assembly.md Outdated Show resolved Hide resolved
specifications/cloud_assembly.md Outdated Show resolved Hide resolved
specifications/cloud_assembly.md Show resolved Hide resolved
specifications/cloud_assembly.md Outdated Show resolved Hide resolved
specifications/cloud_assembly.md Outdated Show resolved Hide resolved
Property |Type |Required|Description
-------------|--------------------|:------:|-----------
`template` |`string` |Required|The assembly-relative path to the *CloudFormation* template document.
`parameters` |`Map<string,string>`| |Parameters to be passed to the [stack][CFN Stack] upon deployment.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the only way to order drops by using the output of one in the parameters of another? We have more need of sequencing stack drops that aren't necessarily expressed as a threading of information from one object to the other (yay, side effects).

For example, an Export in one stack and an Import in the other.

I would argue for a field similar to CloudFormation's DependsOn.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Export/Import is a good case. Although one could say you might want to use Parameters to make the dependency explicit (but you certainly don't have to). I'm adding an optional dependsOn array.

specifications/cloud_assembly.md Outdated Show resolved Hide resolved
specifications/cloud_assembly.md Outdated Show resolved Hide resolved
specifications/cloud_assembly.md Show resolved Hide resolved
Property |Type |Required|Description
------------|--------|:------:|-----------
`savedImage`|`string`|Required|The assembly-relative path to the tar archive obtained from `docker image save`.
`imageName` |`string`|Required|The name of the image (e.g: `000000000000.dkr.ecr.bermuda-triangle-1.amazon.com/name`).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer for this name to be something like pushTarget or something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah these serve mostly as example, so names in here are definitely non-normative and I've been... favoring speed over quality :D

This adds a rule to make sure the codebase is all configured to support
node runtimes complying with `>= 8.11.0`, by ensuring that the
configured `@types/node` version starts with `^8.11.`.

In order to allow applying this rule to the top-level `package.json`, a
feature was added to `pkglint` that allows users to confgure `include`
and `exclude` filters as part of their `package.json`'s `pkglint` setup.
Exclusions always have precedence over inclusions, and specifying
`disable: true` has the same effect as specifying `exclude: '*'`. Both
the `include` and `exclude` values can contain patterns that use `*` as
a wild-card that maches any number of characters (including no
character at all), and can be either a single pattern, or an array of
patterns. `include` defaults to `*`.

In other words, *Logical IDs* are expected to match the following regular expression:
```js
/^[A-Za-z0-9+\/_-]{1,256}$/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it be things like -, +, _, 0 then? Seems a little too permissive maybe?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? I have no problem with those. Their primary goal is not human-readability, it's supposed to be machine-processed. I find expressing "only letters and numbers, -, +, _, but must start by a letter" starts looking like the expression of a poor password policy... I don't want to impose restrictions that are convoluted to express in plain English unless I have a good reason to.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think 0, or -, or + are great logical IDs, but maybe it's just me. Feel free to ignore.

Key |Type |Required|Description
-------------|----------------------|:------:|-----------
`type` |`string` |Required|The [*Drop Type*](#drop-type) specifier of this Drop.
`environment`|`string` |required|The target [environment](#environment) in which Drop is deployed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"in which this Drop is deployed"?

Copy link
Contributor

@skinny85 skinny85 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great :). Some minor comments.

`metadata` |`Map<string,Metadata>`| |Arbitrary named [metadata](#metadata) associated with this Drop.
`properties` |`Map<string,any>` | |The properties of this Drop as documented by its maintainers.

Each [Drop Type](#drop-type) can produce output strings that allow Drops to provide informations that other Drops can
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this paragraph, and the ones below, deserve a separate section. They seem a little too deep after just being introduced to what drops are for the first time.

└───────────── The Logical ID of the Drop
```

The following escape sequences are valid:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where are the escape sequences valid? All strings everywhere in the cloud assembly? Keys, values, both? Would be good to clarify I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. They're only meaningful in places where the interpolation is (aka - values of the properties map).

Deployment systems **MUST** support at least one protocol, and **SHOULD** support all the protocols specified in
the following sub-sections.

##### The `npm` protocol
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree with Rico. Why limit ourselves to a string, when we have the full power of JSON available? I think the Drop Type being an object is more powerful (and easier to extend in the future).

╰┬╯ ╰──┬──╯ ╰──┬─╯
│ │ └─ The name of an AWS region (e.g: eu-west-1)
│ └───────── An AWS account ID (e.g: 123456789012)
└───────────────── AWS protocol specifier
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This already seems not powerful enough (cross-region CodePipelines? Cross-account CodePipelines?).

Again, I would suggest using more of JSON's power here than just a string.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A Drop lives in exactly one account/region. Cross-region / cross-account CodePipelines will involve multiple Drops in different environments.

└───────────────── AWS protocol specifier
```

### Metadata
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, is metadata an object with just 2 keys? Seems quite limiting... what if I have a bunch of warnings/errors for the same file, seems like putting them in a list would be convenient... I would think about this a little more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. I came to realize this as I was trying to implement... :)

@rix0rrr
Copy link
Contributor

rix0rrr commented Jan 15, 2019

What's going on with this PR?

@eladb
Copy link
Contributor

eladb commented Jan 15, 2019

Hold it off for now. We are meeting with CNAB next week and will be wiser after the meeting.

@RomainMuller
Copy link
Contributor Author

Abandoning this for now (resolving without merge).

@RomainMuller RomainMuller deleted the rmuller/cloud-assembly branch February 5, 2019 10:14
@hjander
Copy link

hjander commented Feb 5, 2019

What will be the future direction regarding the Cloudlet/CNAB topic ?

@eladb
Copy link
Contributor

eladb commented Feb 5, 2019

@hjander thanks for querying - @RomainMuller left a comment on #956 -- shall we continue the discussion there?

@eladb eladb changed the title chore: Specify a Cloud Assembly chore: Cloud Assembly Specification Feb 5, 2019
@eladb eladb changed the title chore: Cloud Assembly Specification rfc: Cloud Assembly Specification Feb 5, 2019
eladb pushed a commit that referenced this pull request Feb 27, 2019
Start moving towards the cloud-assembly specification where an output
of a CDK program is a bunch of artifacts and those are processed by
the toolkit.

Related #956
Related #233
Related #1119
@NGL321 NGL321 added the contribution/core This is a PR that came from AWS. label Sep 27, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution/core This is a PR that came from AWS. help wanted We are asking the community to submit a PR to resolve this issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cloud Assembly Specification
7 participants