diff --git a/docs/src/apples_example.rst b/docs/src/apples_example.rst new file mode 100644 index 0000000000000..fb78ea2ca987d --- /dev/null +++ b/docs/src/apples_example.rst @@ -0,0 +1,445 @@ +.. Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 + International License (the "License"). You may not use this file except in compliance with the + License. A copy of the License is located at http://creativecommons.org/licenses/by-nc-sa/4.0/. + + This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + either express or implied. See the License for the specific language governing permissions and + limitations under the License. + +.. _apples_example: + +############## +Apples Example +############## + +This example walks you through creating the resources for a simple widget dispensing service. +It includes: + +* An |LAMlong| function +* An |ABP| API to call our |LAM| function +* An |S3| bucket that contains our |LAM| function code + +.. _overview: + +Overview +======== + +This tutorial contains the following steps. + +1. Create a |cdk| app + +2. Create a |LAM| function that gets a list of widgets with: GET / + +3. Create the service that calls the |LAM| function + +4. Add the service to the |cdk| app + +5. Test the app + +6. Add |LAM| functions to: + + * create an widget based with: POST /{name} + * get an widget by name with: GET /{name} + * delete an widget by name with: DELETE /{name} + +.. _create_app: + +Step 1: Create a |cdk| App +========================== + +Let's create the TypeScript app **MyWidgetService** in in the current folder. + +.. code-block:: sh + + mkdir MyWidgetService + cd MyWidgetService + cdk init --language typescript + +This creates *my_widget_service.ts* in the *bin* directory +and *my_widget_service-stack.ts* in the *lib*. + +Make sure it builds and creates an empty stack. + +.. code-block:: sh + + npm run build + cdk synth + +You should see a stack like the following, +where CDK-VERSION is the version of the CDK. + +.. code-block:: sh + + Resources: + CDKMetadata: + Type: AWS::CDK::Metadata + Properties: + Modules: "@aws-cdk/cdk=CDK-VERSION,@aws-cdk/cx-api=CDK-VERSION,my_widget_service=0.1.0" + +.. _create_lambda_functions: + +Step 2: Create a |LAM| Function to List all Widgets +=================================================== + +The next step is to create a |LAM| function to list all of the widgets in our +|S3| bucket. + +Create the directory *resources* at the same level as the *bin* directory. + +.. code-block:: sh + + mkdir resources + +Create the following Javascript file, *widgets.js*, +in the *resources* directory. + +.. code-block:: js + + const AWS = require('aws-sdk'); + const S3 = new AWS.S3(); + + const bucketName = process.env.BUCKET; + + exports.main = async function(event, context) { + try { + var method = event.httpMethod; + + if (method === "GET") { + if (event.path === "/") { + const data = await S3.listObjectsV2({ Bucket: bucketName }).promise(); + var body = { + widgets: data.Contents.map(function(e) { return e.Key }) + }; + return { + statusCode: 200, + headers: {}, + body: JSON.stringify(body) + }; + } + } + + // We only accept GET for now + return { + statusCode: 400, + headers: {}, + body: "We only accept GET /" + }; + } catch(error) { + var body = error.stack || JSON.stringify(error, null, 2); + return { + statusCode: 400, + headers: {}, + body: JSON.stringify(body) + } + } + } + +Save it and make sure it builds and creates an empty stack. +Note that since we haven't wired the function to our app, +the Lambda file does not appear in the output. + +.. code-block:: sh + + npm run build + cdk synth + +.. _create_widgets_service: + +Step 3: Create Widgets Service +============================== + +Add the |ABP|, |LAM|, and |S3| packages to our app. + +.. code-block:: sh + + npm install @aws-cdk/aws-apigateway @aws-cdk/aws-lambda @aws-cdk/aws-s3 + +Create the following Typescript file, *widget_service.ts*, +in the *lib* directory. + +.. code-block:: ts + + import cdk = require('@aws-cdk/cdk'); + import apigateway = require('@aws-cdk/aws-apigateway'); + import lambda = require('@aws-cdk/aws-lambda'); + import s3 = require('@aws-cdk/aws-s3'); + + export class WidgetService extends cdk.Construct { + constructor(parent: cdk.Construct, name: string) { + super(parent, name); + + // Use S3 bucket to store our widgets + const bucket = new s3.Bucket(this, 'WidgetStore'); + + // Create a handler that calls the function main + // in the source file widgets(.js) in the resources directory + // to handle requests through API Gateway + const handler = new lambda.Function(this, 'WidgetHandler', { + runtime: lambda.Runtime.NodeJS810, + code: lambda.Code.directory('resources'), + handler: 'widgets.main', + environment: { + BUCKET: bucket.bucketName // So runtime has the bucket name + } + }); + + bucket.grantReadWrite(handler.role); + + // Create an API Gateway REST API + const api = new apigateway.RestApi(this, 'widgets-api', { + restApiName: 'Widget Service', + description: 'This service serves widgets.' + }); + + // Pass the request to the handler + const getWidgetsIntegration = new apigateway.LambdaIntegration(handler); + + // Use the getWidgetsIntegration when there is a GET request + api.root.addMethod('GET', getWidgetsIntegration); // GET / + } + } + +Save it and make sure it builds and creates a (still empty) stack. + +.. code-block:: sh + + npm run build + cdk synth + +.. _add_service: + +Step 4: Add the Service to the App +================================== + +To add the service to our app, +we need to first modify *my_widget_service-stack.ts*. +Add the following line of code after the existing **import** statement. + +.. code-block:: ts + + import widget_service = require('../lib/widget_service'); + +Replace the comment in the constructor with the following line of code. + +.. code-block:: ts + + new widget_service.WidgetService(this, 'Widgets'); + +Make sure it builds and creates a stack +(we don't show the stack as it's over 250 lines). + +.. code-block:: sh + + npm run build + cdk synth + +.. _deploy_and_test: + +Step 5: Deploy and Test the App +=============================== + +Before you can deploy your first |cdk| app, +you must bootstrap your deployment, +which creates some AWS infracture that the |cdk| +needs. +See the **bootstrap** section of the :doc:`tools` topic for details +(you'll get a warning and nothing changes if you may have done this already). + +.. code-block:: sh + + cdk bootstrap + +Run the following command to deploy your app. + +.. code-block:: sh + + cdk deploy + +If the deployment is successfull, +save the URL for your server, which appears in one of the last lines in the window, +where GUID is an alpha-numeric GUID and REGION is your region. + +.. code-block:: sh + + https://GUID.execute-REGION.amazonaws.com/prod/ + +You can test your app by getting the list of widgets (currently empty) by navigating to this URL in a +browser or use the following **curl** command. + +.. code-block:: sh + + curl -X GET 'https://GUID.execute-REGION.amazonaws.com/prod' + +You can also open the |console|, +navigate to the |ABP| service, +find **Widget Service** in the list. +Select **GET** and **Test** to test the function. +Since we haven't stored any widgets yet, the output should be similar to the following +(there may be some slight differences in whitespace and quotation marks). + +.. code-block:: sh + + { "widgets": [] } + +.. _adding_functions: + +Step 6: Add the Individual Widget Functions +=========================================== + +The next step is to create |LAM| functions to create, show, and delete +individual widgets. +Replace the existing **exports.main** function in *widgets.js* with the following code. + +.. code-block:: js + + exports.main = async function(event, context) { + try { + var method = event.httpMethod; + // Get name, if present + var widgetName = event.path.startsWith('/') ? event.path.substring(1) : event.path; + + if (method === "GET") { + // GET / to get the names of all widgets + if (event.path === "/") { + const data = await S3.listObjectsV2({ Bucket: bucketName }).promise(); + var body = { + widgets: data.Contents.map(function(e) { return e.Key }) + }; + return { + statusCode: 200, + headers: {}, + body: JSON.stringify(body) + }; + } + + if (widgetName) { + // GET /name to get info on widget name + const data = await S3.getObject({ Bucket: bucketName, Key: widgetName}).promise(); + var body = data.Body.toString('utf-8'); + + return { + statusCode: 200, + headers: {}, + body: JSON.stringify(body) + }; + } + } + + if (method === "POST") { + // POST /name + // Return error if we do not have a name + if (!widgetName) { + return { + statusCode: 400, + headers: {}, + body: "Widget name missing" + }; + } + + // Create some dummy data to populate object + const now = new Date(); + var data = widgetName + " created: " + now; + + var base64data = new Buffer(data, 'binary'); + + await S3.putObject({ + Bucket: bucketName, + Key: widgetName, + Body: base64data, + ContentType: 'application/json' + }).promise(); + + return { + statusCode: 200, + headers: {}, + body: JSON.stringify(event.widgets) + }; + } + + if (method === "DELETE") { + // DELETE /name + // Return an error if we do not have a name + if (!widgetName) { + return { + statusCode: 400, + headers: {}, + body: "Widget name missing" + }; + } + + await S3.deleteObject({ + Bucket: bucketName, Key: widgetName + }).promise(); + + return { + statusCode: 200, + headers: {}, + body: "Successfully deleted widget " + widgetName + }; + } + + // We got something besides a GET, POST, or DELETE + return { + statusCode: 400, + headers: {}, + body: "We only accept GET, POST, and DELETE, not " + method + }; + } catch(error) { + var body = error.stack || JSON.stringify(error, null, 2); + return { + statusCode: 400, + headers: {}, + body: body + } + } + } + +Wire these functions up to our |ABP| code in *widget_service.ts* +by adding the following code at the end of the constructor. + +.. code-block:: ts + + const widget = api.root.addResource('{name}'); + + // Add new widget to bucket with: POST /{name} + const postWidgetIntegration = new apigateway.LambdaIntegration(handler); + + // Get a specific widget from bucket with: GET /{name} + const getWidgetIntegration = new apigateway.LambdaIntegration(handler); + + // Remove a specific widget from the bucket with: DELETE /{name} + const deleteWidgetIntegration = new apigateway.LambdaIntegration(handler); + + widget.addMethod('POST', postWidgetIntegration); // POST /{name} + widget.addMethod('GET', getWidgetIntegration); // GET /{name} + widget.addMethod('DELETE', deleteWidgetIntegration); // DELETE /{name} + +Save, build, and deploy the app. + +.. code-block:: sh + + npm run build + cdk deploy + +Now we should be able to store, show, or delete an individual widget. +Use the following **curl** commands to list the widgets, +create the widget *dummy*, +list all of the widgets, +show the contents of *dummy* (it should show today's date), +and delete *dummy*, +and again show the list of widgets. + +.. code-block:: sh + + curl -X GET 'https://GUID.execute-REGION.amazonaws.com/prod' + curl -X POST 'https://GUID.execute-REGION.amazonaws.com/prod/dummy' + curl -X GET 'https://GUID.execute-REGION.amazonaws.com/prod' + curl -X GET 'https://GUID.execute-REGION.amazonaws.com/prod/dummy' + curl -X DELETE 'https://GUID.execute-REGION.amazonaws.com/prod/dummy' + curl -X GET 'https://GUID.execute-REGION.amazonaws.com/prod' + +You can also use the |ABP| console to test these functions. +You'll have to set the **name** entry to the name of an widget, +such as **dummy**. diff --git a/docs/src/aws-construct-lib.rst b/docs/src/aws-construct-lib.rst index 79b08c204a720..9804dc9eb5f24 100644 --- a/docs/src/aws-construct-lib.rst +++ b/docs/src/aws-construct-lib.rst @@ -329,21 +329,23 @@ Synthesizes to: .. code-block:: json - "MyBucketF68F3FF0": { - "Type": "AWS::S3::Bucket", - "Properties": { - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "EncryptEverythingAndAlways": true - } - ] - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - } - } + { + "MyBucketF68F3FF0": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "EncryptEverythingAndAlways": true + } + ] + }, + "VersioningConfiguration": { + "Status": "Enabled" + } + } + } + } Directly Defining CloudFormation Resources ------------------------------------------- diff --git a/docs/src/ecs_example.rst b/docs/src/ecs_example.rst new file mode 100644 index 0000000000000..d5202c9267e61 --- /dev/null +++ b/docs/src/ecs_example.rst @@ -0,0 +1,200 @@ +.. Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + + This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 + International License (the "License"). You may not use this file except in compliance with the + License. A copy of the License is located at http://creativecommons.org/licenses/by-nc-sa/4.0/. + + This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + either express or implied. See the License for the specific language governing permissions and + limitations under the License. + +.. _ecs_example: + +############# +|ECS| Example +############# + +This example walks you through creating a Fargate service running on an ECS cluster fronted by an internet-facing +application load balancer. + +|ECSlong| (|ECS|) is a highly scalable, fast, container management service +that makes it easy to run, stop, and manage Docker containers on a cluster. +You can host your cluster on a serverless infrastructure that is managed by +|ECS| by launching your services or tasks using the Fargate launch type. +For more control you can host your tasks on a cluster of +|EC2long| (|EC2|) instances that you manage by using the EC2 launch type. + +This example shows you how to launch some services using the Fargate launch type. +If you've ever used the console to create a Fargate service, +you know that there are many steps you must follow to accomplish that task. +AWS has a number of tutorials and documentation topics that walk you through +creating a Fargate service, +including: + +* `How to Deploy Docker Containers - AWS `_ + +* `Setting up with Amazon ECS `_ and + `Getting Started with Amazon ECS using Fargate `_ + +This example creates a similar Fargate service in |cdk| code. + +Since |ECS| can be used with a number of AWS services, +you should understand how the |ECS| construct that we use in this example +gives you a leg up on using AWS services by providing the following benefits: + +* Automatically configures a load balancer. + +* Automatic security group opening for load balancers, + which enables load balancers to communicate with instances + without you explictly creating a security group. + +* Automatic ordering dependency between service and load balancer attaching to a target group, + where the |cdk| enforces the correct order of creating the listener before an instance is created + +* Automatic userdata configuration on auto-scaling group, + which creates the correct configuration to associate a cluster to AMI(s). + +* Early validation of parameter combinations, which exposes |CFN| issues earlier, thus saving you deployment time. + For example, depending upon the task, it is easy to mis-configure the memory settings. + Previously you would not encounter an error until you deployed your app, + but now the |cdk| can detect a misconfiguration and emit an error when you synthesize your app. + +* Automatically adds permissions for |ECR| if you use an image from |ECR| + When you use an image from |ECR|, the |cdk| adds the correct permissions. + +* Automatic autoscaling + The |cdk| supplies a method so you can autoscaling instances when you use an |EC2| cluster; + this functionality is done automatically when you use an instance in a Fargate cluster. + + In addition, the |cdk| will prevent instances from being deleted when + autoscaling tries to kill an instance, + but either a task is running or is scheduled on that instance. + + Previously, you had to create a Lambda function to have this functionality. + +* Asset support, so that you can deploy source from your machine to |ECS| in one step + Previously, to use application source you had to perform a number of manual steps + (upload to |ECR|, create Docker image, etc.). + +.. _creating_ecs_l2_example_1: + +Step 1: Create the Directory and Initialize the |cdk| +----------------------------------------------------- + +Let's start with creating a new directory to hold our |cdk| code +and create a new app in that directory. + +.. code-block:: sh + + mkdir MyEcsConstruct + cd MyEcsConstruct + +.. tabs:: + + .. group-tab:: TypeScript + + .. code-block:: sh + + cdk init --language typescript + + Build the app and confirm that it creates an empty stack. + + .. code-block:: sh + + npm run build + cdk synth + + You should see a stack like the following, + where CDK-VERSION is the version of the CDK. + + .. code-block:: sh + + Resources: + CDKMetadata: + Type: 'AWS::CDK::Metadata' + Properties: + Modules: @aws-cdk/cdk=CDK-VERSION,@aws-cdk/cx-api=CDK-VERSION,my_ecs_construct=0.1.0 + +.. _creating_ecs_l2_example_2: + +Step 2: Add the |EC2| and |ECS| Packages +---------------------------------------- + +Install support for |EC2| and |ECS|. + +.. tabs:: + + .. group-tab:: TypeScript + + .. code-block:: sh + + npm install @aws-cdk/aws-ec2 @aws-cdk/aws-ecs + +.. _creating_ecs_l2_example_3: + +Step 3: Create a Fargate Service +-------------------------------- + +There are two different ways of running your container tasks with |ECS|: + +- Using the **Fargate** launch type, + where |ECS| manages the physical machines that your containers are running on for you +- Using the **EC2** launch type, where you do the managing, such as specifying autoscaling + +The following example creates a Fargate service running on an ECS cluster fronted by an internet-facing +application load balancer. + +.. tabs:: + + .. group-tab:: TypeScript + + Add the following import statements to *lib/my_ecs_construct-stack.ts*: + + .. code-block:: typescript + + import ec2 = require('@aws-cdk/aws-ec2'); + import ecs = require('@aws-cdk/aws-ecs'); + + Replace the comment at the end of the constructor with the following code: + + .. code-block:: typescript + + const vpc = new ec2.VpcNetwork(this, 'MyVpc', { + maxAZs: 3 // Default is all AZs in region + }); + + const cluster = new ecs.Cluster(this, 'MyCluster', { + vpc: vpc + }); + + // Create a load-balanced Fargate service and make it public + new ecs.LoadBalancedFargateService(this, 'MyFargateService', { + cluster: cluster, // Required + cpu: '512', // Default is 256 + desiredCount: 6, // Default is 1 + image: ecs.ContainerImage.fromDockerHub('amazon/amazon-ecs-sample'), // Required + memoryMiB: '2048', // Default is 512 + publicLoadBalancer: true // Default is false + }); + + Save it and make sure it builds and creates a stack. + + .. code-block:: sh + + npm run build + cdk synth + + The stack is hundreds of lines, so we won't show it here. + The stack should contain one default instance, a private subnet and a public subnet + for the three availability zones, and a security group. + + Deploy the stack. + + .. code-block:: sh + + cdk deploy + + |CFN| displays information about the dozens of steps that + it takes as it deploys your app. + +That's how easy it is to create a Fargate service to run a Docker image. diff --git a/docs/src/examples.rst b/docs/src/examples.rst index 83b59db043b30..fc5876b556925 100644 --- a/docs/src/examples.rst +++ b/docs/src/examples.rst @@ -17,6 +17,18 @@ This topic contains some examples to help you get started using some of the advanced constructs offered by the |cdk|. +* :doc:`ecs_example` walks you through creating a Fargate service running on an ECS cluster fronted by an internet-facing +application load balancer. + +* :doc:`apples_example` walks you through creating the resources for a simple widget dispensing service. + +.. toctree:: + :maxdepth: 2 + :hidden: + + ECS Example + Apples Example + .. _creating_ecs_l2_example: Creating an |ECS| |cdk| App diff --git a/docs/src/getting-started.rst b/docs/src/getting-started.rst index f4974f65838a4..211f670613e4e 100644 --- a/docs/src/getting-started.rst +++ b/docs/src/getting-started.rst @@ -10,18 +10,21 @@ .. _getting_started: -##################################### -Creating Your First |cdk| Application -##################################### +############################## +Getting Started with the |cdk| +############################## -This topic walks you through creating and deploying your first |cdk| app. +This topic describes how to download, install, and configure the |cdk|. -.. _setup: +.. _installing_cdk: -Setting up the |cdk| +Installing the |cdk| ==================== -.. _setup_prerequisites: +This section describes how to install the |cdk|, +and lists the prerequsites for each supported language. + +.. _installing_prerequisites: Prerequisites ------------- @@ -39,7 +42,7 @@ You must specify both your credentials and a region to use the toolkit. See :ref:`credentials ` for information on using the AWS CLI to specify your credentials. -.. _setup_install: +.. _installing_toolkit: Installing the Command-Line Toolkit ----------------------------------- @@ -57,342 +60,25 @@ Run the following command to see the currently installed version of the toolkit cdk --version -.. _initializing: - -Initializing the Project -======================== - -.. note:: - - This guide walks you through the process of creating an |cdk| project. - You can also use the - :code:`cdk init` command to create a skeleton project from a - template in any of the supported languages. - -Create an empty project structure for the |cdk| app. - -.. The cdk init -l typescript version of package.json also includes - a "cdk": "cdk" - entry in "scripts" - -.. tabs:: - - .. group-tab:: C# - - Create a new empty, source controlled directory and then create a new - console application. - - .. code-block:: sh - - mkdir HelloCdk - cd HelloCdk - dotnet new console - - .. group-tab:: JavaScript - - Create an empty source-controlled directory for your project and an - initial npm **package.json** file: - - .. code-block:: sh - - mkdir hello-cdk - cd hello-cdk - git init - npm init -y # creates package.json - - Create a **.gitignore** file with the following content: - - .. code-block:: sh - - *.js - node_modules - - .. group-tab:: TypeScript - - Create an empty source-controlled directory for your project and an - initial npm **package.json** file: - - .. code-block:: sh - - mkdir hello-cdk - cd hello-cdk - git init - npm init -y # creates package.json - - Create a **.gitignore** file with the following content: - - .. code-block:: sh - - *.js - *.d.ts - node_modules - - Add the `build` and `watch` TypeScript commands to **package.json**: - - .. code-block:: json - - { - "scripts": { - "build": "tsc", - "watch": "tsc -w" - } - } - - Create a minimal **tsconfig.json**: - - .. code-block:: json - - { - "compilerOptions": { - "target": "es2018", - "module": "commonjs" - } - } - - .. group-tab:: Java - - Create an empty source-controlled directory for your project: - - .. code-block:: sh - - mkdir hello-cdk - cd hello-cdk - git init - - Create a **.gitignore** file with the following content: - - .. code-block:: sh - - .classpath.txt - target - .classpath - .project - .idea - .settings - .vscode - *.iml - - Use your favorite IDE to create a Maven-based empty Java 8 project. - - Set the Java **source** and **target** to 1.8 in your **pom.xml** file: - - .. code-block:: xml - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.1 - - 1.8 - 1.8 - - - - - -.. _add_core: - -Adding @aws-cdk/cdk as a Dependency -=================================== - -Install the |cdk| core library (:py:mod:`@aws-cdk/cdk`). This -library includes the basic classes needed to write |cdk| stacks and apps. - -.. tabs:: - - .. group-tab:: C# - - Install the **Amazon.CDK NuGet** package: - - .. code-block:: sh - - dotnet add package Amazon.CDK - - .. group-tab:: JavaScript - - Install the **@aws-cdk/cdk** package: - - .. code-block:: sh - - npm install @aws-cdk/cdk - - .. group-tab:: TypeScript - - Install the **@aws-cdk/cdk** package: - - .. code-block:: sh - - npm install @aws-cdk/cdk - - .. group-tab:: Java - - Add the following to your project's `pom.xml` file: - - .. code-block:: xml - - - - software.amazon.awscdk - cdk - - - - -.. _define_app: - -Defining the |cdk| App -====================== - -|cdk| apps are classes that extend the :py:class:`App <@aws-cdk/cdk.App>` -class. Create an empty **App**: - -.. tabs:: - - .. group-tab:: C# - - In **Program.cs** - - .. code-block:: c# - - using Amazon.CDK; - - namespace HelloCdk - { - class Program - { - static void Main(string[] args) - { - var myApp = new App(); - myApp.Run(); - } - } - } - - .. group-tab:: JavaScript - - Create the file **bin/hello-cdk.js**: - - .. code-block:: js - - const cdk = require('@aws-cdk/cdk'); - - class MyApp extends cdk.App { - constructor() { - super(); - } - } - - new MyApp().run(); - - .. group-tab:: TypeScript - - Create the file **bin/hello-cdk.ts**: - - .. code-block:: ts - - import cdk = require('@aws-cdk/cdk'); - - class MyApp extends cdk.App { - constructor() { - super(); - } - } - - new MyApp().run(); - - .. group-tab:: Java - - In **src/main/java/com/acme/MyApp.java**: - - .. code-block:: java - - package com.acme; - - import software.amazon.awscdk.App; - - import java.util.Arrays; - - public class MyApp { - public static void main(final String argv[]) { - App app = new App(); - - app.run(); - } - } - -.. _complie_code: - -Compiling the Code -================== - -If needed, compile the code: - -.. tabs:: - - .. group-tab:: C# - - Compile the code using your IDE or via the dotnet CLI: - - .. code-block:: sh - - dotnet build - - .. group-tab:: JavaScript - - No need to compile - - .. group-tab:: TypeScript - - To compile your program from **.ts** to **.js**: - - .. code-block:: sh - - npm run build - - You can also use the **watch** command to continuously compile your code - as it changes, so you don't have to invoke the compiler explicitly: - - .. code-block:: sh - - # run in another terminal session - npm run watch - - .. group-tab:: Java - - Compile your code using your IDE or via the command line via **mvn**: - - .. code-block:: sh - - mvn compile - -You have now created your first |cdk| app. - .. _credentials: -Configuring the |cdk| Toolkit -============================= - -Use the |cdk| toolkit to view the contents of an app. - -.. note:: +Configuring the |cdk| +===================== - You must specify your default credentials and region to use the toolkit. +You must specify your default credentials and region to use the toolkit. - Use the `AWS Command Line Interface `_ - ``aws configure`` command to specify your default credentials and region. +Use the `AWS Command Line Interface `_ +``aws configure`` command to specify your default credentials and region. - You can also set environment variables for your default credentials and region. - Environment variables take precedence over settings in the credentials or config file. +You can also set environment variables for your default credentials and region. +Environment variables take precedence over settings in the credentials or config file. - * *AWS_ACCESS_KEY_ID* specifies your access key - * *AWS_SECRET_ACCESS_KEY* specifies your secret access key - * *AWS_DEFAULT_REGION* specifies your default region +* *AWS_ACCESS_KEY_ID* specifies your access key +* *AWS_SECRET_ACCESS_KEY* specifies your secret access key +* *AWS_DEFAULT_REGION* specifies your default region - See `Environment Variables `_ - in the CLI User Guide for details. +See `Environment Variables `_ +in the CLI User Guide for details. .. include:: region-note.rst @@ -495,604 +181,3 @@ your project directory with the following content: "app": "/bin/bash ./app.sh" } -.. _list_stacks: - -List the Stacks in the App -========================== - -Use the |cdk| toolkit's **ls** command to list the stacks in the app. - -.. code-block:: sh - - cdk ls -l - -The result is an empty array: - -.. code-block:: sh - - [] - -An empty array makes sense, since our app doesn't have any stacks. - -.. note:: - - There is a known issue on Windows with the |cdk| .NET environment. - Whenever you use a **cdk** command, - it issues a node warning similar to the following: - - .. code-block:: sh - - (node:27508) UnhandledPromiseRejectionWarning: Unhandled promise rejection - (rejection id: 1): Error: EPIPE: broken pipe, write - (node:27508) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. - In the future, promise rejections that are not handled will terminate the - Node.js process with a non-zero exit code. - - You can safely ignore this warning. - -.. _define_stack: - -Define a Stack -============== - -Define a stack and add it to the app. - -.. tabs:: - - .. group-tab:: C# - - Create **MyStack.cs**: - - .. code-block:: c# - - using Amazon.CDK; - - namespace HelloCdk - { - public class MyStack: Stack - { - public MyStack(App parent, string name) : base(parent, name, null) - { - } - } - } - - In **Program.cs**: - - .. code-block:: c# - :emphasize-lines: 10 - - using Amazon.CDK; - - namespace HelloCdk - { - class Program - { - static void Main(string[] args) - { - var myApp = new App(); - new MyStack(myApp, "hello-cdk"); - myApp.Run(); - } - } - } - - .. group-tab:: JavaScript - - In **index.js**: - - .. code-block:: js - :emphasize-lines: 3,4,5,6,7,13 - - const cdk = require('@aws-cdk/cdk'); - - class MyStack extends cdk.Stack { - constructor(parent, id, props) { - super(parent, id, props); - } - } - - class MyApp extends cdk.App { - constructor(argv) { - super(argv); - - new MyStack(this, 'hello-cdk'); - } - } - - new MyApp().run(); - - .. group-tab:: TypeScript - - In **index.ts**: - - .. code-block:: ts - :emphasize-lines: 3,4,5,6,7,13 - - import cdk = require('@aws-cdk/cdk'); - - class MyStack extends cdk.Stack { - constructor(parent: cdk.App, id: string, props?: cdk.StackProps) { - super(parent, id, props); - } - } - - class MyApp extends cdk.App { - constructor() { - super(); - new MyStack(this, 'hello-cdk'); - } - } - - new MyApp().run(); - - .. group-tab:: Java - - In **src/main/java/com/acme/MyStack.java**: - - .. code-block:: java - - package com.acme; - - import software.amazon.awscdk.App; - import software.amazon.awscdk.Stack; - import software.amazon.awscdk.StackProps; - - public class MyStack extends Stack { - public MyStack(final App parent, final String name) { - this(parent, name, null); - } - - public MyStack(final App parent, final String name, final StackProps props) { - super(parent, name, props); - } - } - - In **src/main/java/com/acme/MyApp.java**: - - .. code-block:: java - :emphasize-lines: 12 - - package com.acme; - - import software.amazon.awscdk.App; - import java.util.Arrays; - - public class MyApp { - public static void main(final String argv[]) { - App app = new App(); - - new MyStack(app, "hello-cdk"); - - app.run(); - } - } - -The initializer signature of **cdk.Stack** includes the arguments: **parent**, -**id**, and **props**. This is the signature for every class in the |cdk| -framework. These classes are called **"constructs"** and they are composed -together into a tree: - -* **parent** represents the parent construct. By specifying the parent construct - upon initialization, constructs can obtain contextual information when they - are initialized. For example, the region a stack is deployed to can be - obtained via a call to :py:meth:`Stack.find(this).requireRegion() <@aws-cdk/cdk.Stack.requireRegion>`. - See :doc:`context` for more information. -* **id** is a string that locally identifies this construct within the tree. - Constructs must have a unique ID amongst their siblings. -* **props** is the set of initialization properties for this construct. - -Compile your program: - -.. tabs:: - - .. group-tab:: C# - - We have configured cdk.json to run "dotnet run", which will - restore dependencies, build, and run your application. - Therefore, you just need to run the CDK command. - - .. group-tab:: JavaScript - - Nothing to compile. - - .. group-tab:: TypeScript - - .. code-block:: sh - - npm run build - - .. group-tab:: Java - - .. code-block:: sh - - mvn compile - -Run **cdk ls** to see that the app includes a single -stack: - -.. code-block:: sh - - cdk ls -l - - - name: hello-cdk - environment: - name: / - account: '' - region: - -Notice that your stack has been automatically associated with the default AWS -account and region configured in the AWS CLI. See :doc:`environments` for more -details on how to associate stacks to environments. - -.. _define_bucket: - -Define an |S3| Bucket -===================== - -Now, what can we do with this app? Nothing yet. Our stack is still empty, so -there's nothing to deploy. - -Let's define an |S3| bucket. - -Install the **@aws-cdk/aws-s3** package: - -.. tabs:: - - .. group-tab:: C# - - .. code-block:: sh - - dotnet add package Amazon.CDK.AWS.S3 - - .. group-tab:: JavaScript - - .. code-block:: sh - - npm install @aws-cdk/aws-s3 - - .. group-tab:: TypeScript - - .. code-block:: sh - - npm install @aws-cdk/aws-s3 - - .. group-tab:: Java - - Edit your **pom.xml** file: - - .. code-block:: sh - - - software.amazon.awscdk - s3 - - - -Next, define an |S3| bucket in the stack. |S3| buckets are represented by -the :py:class:`Bucket <@aws-cdk/aws-s3.Bucket>` class: - -.. tabs:: - - .. group-tab:: C# - - Create **MyStack.cs**: - - .. code-block:: c# - :emphasize-lines: 2,10,11,12,13 - - using Amazon.CDK; - using Amazon.CDK.AWS.S3; - - namespace HelloCdk - { - public class MyStack : Stack - { - public MyStack(App parent, string name) : base(parent, name, null) - { - new Bucket(this, "MyFirstBucket", new BucketProps - { - Versioned = true - }); - } - } - } - - .. group-tab:: JavaScript - - In **index.js**: - - .. code-block:: js - :emphasize-lines: 2,8,9,10 - - const cdk = require('@aws-cdk/cdk'); - const s3 = require('@aws-cdk/aws-s3'); - - class MyStack extends cdk.Stack { - constructor(parent, id, props) { - super(parent, id, props); - - new s3.Bucket(this, 'MyFirstBucket', { - versioned: true - }); - } - } - - .. group-tab:: TypeScript - - In **index.ts**: - - .. code-block:: ts - :emphasize-lines: 2,8,9,10 - - import cdk = require('@aws-cdk/cdk'); - import s3 = require('@aws-cdk/aws-s3'); - - class MyStack extends cdk.Stack { - constructor(parent: cdk.App, id: string, props?: cdk.StackProps) { - super(parent, id, props); - - new s3.Bucket(this, 'MyFirstBucket', { - versioned: true - }); - } - } - - .. group-tab:: Java - - In **src/main/java/com/acme/MyStack.java**: - - .. code-block:: java - :emphasize-lines: 6,7,13,14,15 - - package com.acme; - - import software.amazon.awscdk.App; - import software.amazon.awscdk.Stack; - import software.amazon.awscdk.StackProps; - import software.amazon.awscdk.services.s3.Bucket; - import software.amazon.awscdk.services.s3.BucketProps; - - public class MyStack extends Stack { - public MyStack(final App parent, final String name) { - this(parent, name, null); - } - - public MyStack(final App parent, final String name, final StackProps props) { - super(parent, name, props); - - new Bucket(this, "MyFirstBucket", BucketProps.builder() - .withVersioned(true) - .build()); - } - } - -A few things to notice: - -* :py:class:`Bucket <@aws-cdk/aws-s3.Bucket>` is a construct. - This means it's initialization signature has **parent**, **id**, and **props**. - In this case, the bucket is an immediate child of **MyStack**. -* ``MyFirstBucket`` is the **logical id** of the bucket construct, **not** the physical name of the - S3 bucket. The logical ID is used to uniquely identify resources in your stack - across deployments. See :doc:`logical-ids` for more details on how to work - with logical IDs. To specify a physical name for your bucket, you can set the - :py:meth:`bucketName <@aws-cdk/aws-s3.BucketProps.bucketName>` property when - you define your bucket. -* Since the bucket's :py:meth:`versioned <@aws-cdk/aws-s3.BucketProps.versioned>` - property is :code:`true`, `versioning `_ - is enabled on the bucket. - -Compile your program: - -.. tabs:: - - .. group-tab:: C# - - We have configured cdk.json to run "dotnet run", which will - restore dependencies, build, and run your application. - Therefore, you just need to run the CDK command. - - .. group-tab:: JavaScript - - Nothing to compile. - - .. group-tab:: TypeScript - - .. code-block:: sh - - npm run build - - .. group-tab:: Java - - .. code-block:: sh - - mvn compile - -.. _synthesize_template: - -Synthesize an |CFN| Template -============================ - -Synthesize a |cfn| template for the stack: - -.. code-block:: sh - - cdk synth hello-cdk - -.. note:: Since the |cdk| app only contains a single stack, you can omit :code:`hello-cdk`. - -This command executes the |cdk| app and synthesize an |CFN| template for the -**hello-cdk** stack: - -.. code-block:: yaml - - Resources: - MyFirstBucketB8884501: - Type: 'AWS::S3::Bucket' - Properties: - VersioningConfiguration: - Status: Enabled - CDKMetadata: - Type: 'AWS::CDK::Metadata' - Properties: - Modules: # ... - -You can see that the stack contains an **AWS::S3::Bucket** resource with the desired -versioning configuration. - -.. note:: - - The **AWS::CDK::Metadata** resource was automatically added to your template - by the toolkit. This allows us to learn which libraries were used in your - stack. See :ref:`version-reporting` for more details and how to - :ref:`opt-out `. - -.. _deploy_stack: - -Deploying the Stack -=================== - -Use **cdk deploy** to deploy the stack: - -.. code-block:: sh - - cdk deploy - -The **deploy** command synthesizes an |CFN| template from the stack -and then invokes the |CFN| create/update API to deploy it into your AWS -account. The command displays information as it progresses. - -.. _modify_cde: - -Modifying the Code -================== - -Configure the bucket to use KMS managed encryption: - -.. tabs:: - - .. group-tab:: C# - - .. code-block:: c# - :emphasize-lines: 4 - - new Bucket(this, "MyFirstBucket", new BucketProps - { - Versioned = true, - Encryption = BucketEncryption.KmsManaged - }); - - .. group-tab:: JavaScript - - .. code-block:: js - :emphasize-lines: 3 - - new s3.Bucket(this, 'MyFirstBucket', { - versioned: true, - encryption: s3.BucketEncryption.KmsManaged - }); - - .. group-tab:: TypeScript - - .. code-block:: ts - :emphasize-lines: 3 - - new s3.Bucket(this, 'MyFirstBucket', { - versioned: true, - encryption: s3.BucketEncryption.KmsManaged - }); - - .. group-tab:: Java - - .. code-block:: java - :emphasize-lines: 3 - - new Bucket(this, "MyFirstBucket", BucketProps.builder() - .withVersioned(true) - .withEncryption(BucketEncryption.KmsManaged) - .build()); - -Compile the program: - -.. tabs:: - - .. group-tab:: C# - - We have configured cdk.json to run "dotnet run", which will - restore dependencies, build, and run your application. - Therefore, you just need to run the CDK command. - - .. group-tab:: JavaScript - - Nothing to compile. - - .. group-tab:: TypeScript - - .. code-block:: sh - - npm run build - - .. group-tab:: Java - - .. code-block:: sh - - mvn compile - -.. _prepare_deployment: - -Preparing for Deployment -======================== - -Before you deploy the updated stack, use the ``cdk diff`` command to evaluate -the difference between the |cdk| app and the deployed stack: - -.. code-block:: sh - - cdk diff - -The toolkit queries your AWS account for the current |CFN| template for the -**hello-cdk** stack, and compares the result with the template synthesized from the app. -The output should look like the following: - -.. code-block:: sh - - [~] 🛠 Updating MyFirstBucketB8884501 (type: AWS::S3::Bucket) - └─ [+] .BucketEncryption: - └─ New value: {"ServerSideEncryptionConfiguration":[{"ServerSideEncryptionByDefault":{"SSEAlgorithm":"aws:kms"}}]} - -As you can see, the diff indicates that the -**ServerSideEncryptionConfiguration** property of the bucket is now set to -enable server-side encryption. - -You can also see that the bucket is not going to be replaced but rather updated -("**Updating MyFirstBucketB8884501**"). - -Run **cdk deploy** to update the stack: - -.. code-block:: sh - - cdk deploy - -The toolkit updates the bucket configuration to enable server-side KMS -encryption for the bucket: - -.. code-block:: sh - - ⏳ Starting deployment of stack hello-cdk... - [0/2] UPDATE_IN_PROGRESS [AWS::S3::Bucket] MyFirstBucketB8884501 - [1/2] UPDATE_COMPLETE [AWS::S3::Bucket] MyFirstBucketB8884501 - [1/2] UPDATE_COMPLETE_CLEANUP_IN_PROGRESS [AWS::CloudFormation::Stack] hello-cdk - [2/2] UPDATE_COMPLETE [AWS::CloudFormation::Stack] hello-cdk - ✅ Deployment of stack hello-cdk completed successfully - -.. _whats_next: - -What Next? -========== - - * Learn more about :doc:`CDK Concepts ` - * Check out the `examples directory `_ in your GitHub repository - * Learn about the rich APIs offered by the :doc:`AWS Construct Library ` - * Work directly with CloudFormation using the :doc:`AWS CloudFormation Library ` - * Come talk to us on `Gitter `_ - diff --git a/docs/src/index.rst b/docs/src/index.rst index facc8ca48aa67..109981a62d3cf 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -22,6 +22,19 @@ To get started see :doc:`getting-started` .. image:: screencast.gif +.. npm install -g aws-cdk + ADDED: mkdir ~/hello-cdk; cd ~/hello-cdk + cdk init --language typescript + npm run build + ADDED: cdk synth + cdk deploy + ADDED: + vim bin/aws-cdk.ts -> lib/hello-cdk-stack.ts + // add SNS, SQS, queue, topic, topic.subscribeQueue + cdk diff + cdk deploy + cdk diff + Developers can use one of the supported programming languages to define reusable cloud components called :doc:`constructs`, which are composed together into :doc:`stacks` and :doc:`apps`. @@ -63,10 +76,11 @@ In addition to this guide, the following are other resources available to |cdk| * `Stack Overflow `_ * `GitHub repository `_ + * `License `_ + * `Issues `_ + * `Releases `_ * `Examples `_ * `Documentation source `_ - * `Issues `_ - * `License `_ * `AWS CDK Sample for Cloud9 `_ * `AWS CloudFormation Concepts `_ @@ -94,10 +108,10 @@ To obtain an AWS account, go to `aws.amazon.com `_ and c Getting Started Tutorial + Examples Concepts AWS Construct Library AWS CloudFormation Library - Examples Tools Writing Constructs Reference diff --git a/docs/src/passing-in-data.rst b/docs/src/passing-in-data.rst index 172325d35e369..5f146e8a74a36 100644 --- a/docs/src/passing-in-data.rst +++ b/docs/src/passing-in-data.rst @@ -253,12 +253,14 @@ where **S3Bucket** is the logical ID of the bucket in your template: .. code-block:: json - "S3Bucket": { - "Type": "AWS::S3::Bucket", - "Properties": { - ... - } - } + { + "S3Bucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "prop1": "value1" + } + } + } You can include this bucket in your |cdk| app, as shown in the following example diff --git a/docs/src/region-note.rst b/docs/src/region-note.rst index a69e31af4170f..9dc7e361dc061 100644 --- a/docs/src/region-note.rst +++ b/docs/src/region-note.rst @@ -12,5 +12,5 @@ The China regions (cn-north-1 and cn-northwest-1) do not support version reporting. - See :ref:`version-reporting` for more details and how to - :ref:`opt-out ` + See :ref:`version_reporting` for more details and how to + :ref:`opt-out ` diff --git a/docs/src/tools.rst b/docs/src/tools.rst index c18fba36d43b3..7b47d30f831c9 100644 --- a/docs/src/tools.rst +++ b/docs/src/tools.rst @@ -149,7 +149,7 @@ The ``AWS::CDK::Metadata`` resource looks like the following: Properties: Modules: "@aws-cdk/core=0.7.2-beta,@aws-cdk/s3=0.7.2-beta,lodash=4.17.10" -.. _version-reporting-opt-out: +.. _version_reporting_opt_out: Opting-out from Version Reporting --------------------------------- diff --git a/docs/src/tutorial.rst b/docs/src/tutorial.rst index ef2be74938b61..39befa9b408b1 100644 --- a/docs/src/tutorial.rst +++ b/docs/src/tutorial.rst @@ -10,456 +10,979 @@ .. _tutorial: -############## -|cdk| Tutorial -############## +####################################### +Tutorial: Creating an |cdk| Application +####################################### -This topic steps you through creating the resources for a simple widget dispensing -service using the |cdk|. +This topic walks you through creating and deploying an |cdk| app, +by using the `cdk init` command, as described in the +`Creating a Project from the Template`_ section, +or manually, as described in the +`Creating a Project Manually`_ section. -.. _overview: +In either case, the first step is to create the directory for your project, +with an empty Git repository. +All of these instructions use this directory: -Overview -======== +.. code-block:: sh -This tutorial contains the following steps. + mkdir hello-cdk + cd hello-cdk + git init -1. Create a |cdk| app +.. _template_create_project: -2. Create a |LAMlong| function that gets a list of widgets with: GET / +Creating a Project from the Template +==================================== -3. Create the service that calls the |LAM| function +In this section we use the :code:`cdk init` command to create a skeleton project from a +template in any of the supported languages. -4. Add the service to the |cdk| app +.. _template_initialize: -5. Test the app +Initializing the Project +------------------------ -6. Add |LAM| functions to: +Run the `cdk init` command to initialize an empty project. +The |cdk| contains templates for all of the supported languages. +To create an empty (no AWS resources in the resulting |CFN| stack), +run the following command, where LANGUAGE is one of the supported programming languages: +**csharp** (C#), **java** (Java), or **typescript** (TypeScript). - * create an widget based with: POST /{name} - * get an widget by name with: GET /{name} - * delete an widget by name with: DELETE /{name} +.. code-block:: sh -.. _create_app: + cdk init --language LANGUAGE -Step 1: Create a |cdk| App -========================== +.. _template_compile: -Let's create the TypeScript app **MyWidgetService** in in the current folder. +Compiling the Project +--------------------- -.. code-block:: sh +If needed, compile the code: - mkdir MyWidgetService - cd MyWidgetService - cdk init --language typescript +.. tabs:: -This creates *my_widget_service.ts* in the *bin* directory. -We don't need most of this code, -so for now change it to the following: + .. group-tab:: C# -.. code-block:: ts + Compile the code using your IDE or via the dotnet CLI: - #!/usr/bin/env node - import cdk = require('@aws-cdk/cdk'); + .. code-block:: sh - class MyWidgetServiceStack extends cdk.Stack { - constructor(parent: cdk.App, name: string, props?: cdk.StackProps) { - super(parent, name, props); + dotnet build + .. group-tab:: JavaScript - } - } + No need to compile - // Create a new CDK app - const app = new cdk.App(); + .. group-tab:: TypeScript - // Add your stack to it - new MyWidgetServiceStack(app, 'MyWidgetServiceStack'); + To compile your program from **.ts** to **.js**: - app.run(); + .. code-block:: sh -Save it and make sure it builds and creates an empty stack. + npm run build -.. code-block:: sh + You can also use the **watch** command to continuously compile your code + as it changes, so you don't have to invoke the compiler explicitly: - npm run build - cdk synth + .. code-block:: sh -You should see a stack like the following, -where CDK-VERSION is the version of the CDK. + # run in another terminal session + npm run watch -.. code-block:: sh + .. group-tab:: Java - Resources: - CDKMetadata: - Type: 'AWS::CDK::Metadata' - Properties: - Modules: >- - @aws-cdk/cdk=CDK-VERSION,@aws-cdk/cx-api=CDK-VERSION,my_widget_service=0.1.0 + Compile your code using your IDE or via the command line via **mvn**: -.. _create_lambda_functions: + .. code-block:: sh -Step 2: Create a |LAM| Function to List all Widgets -=================================================== + mvn compile -The next step is to create a |LAM| function to list all of the widgets in our -|S3| bucket. +You have now created your first |cdk| app. +The next section creates a similar app manually, +so you can skip it and continue with the +`Listing the Stacks in the App`_ section. -Create the directory *resources* at the same level as the *bin* directory. +.. _manual_create_project: -.. code-block:: sh +Creating a Project Manually +=========================== - mkdir resources - -Create the following Javascript file, *widgets.js*, -in the *resources* directory. - -.. code-block:: js - - const AWS = require('aws-sdk'); - const S3 = new AWS.S3(); - - const bucketName = process.env.BUCKET; - - exports.main = async function(event, context) { - try { - var method = event.httpMethod; - - if (method === "GET") { - if (event.path === "/") { - const data = await S3.listObjectsV2({ Bucket: bucketName }).promise(); - var body = { - widgets: data.Contents.map(function(e) { return e.Key }) - }; - return { - statusCode: 200, - headers: {}, - body: JSON.stringify(body) - }; - } - } - - // We only accept GET for now - return { - statusCode: 400, - headers: {}, - body: "We only accept GET /" - }; - } catch(error) { - var body = error.stack || JSON.stringify(error, null, 2); - return { - statusCode: 400, - headers: {}, - body: JSON.stringify(body) - } - } - } - -Save it and make sure it builds and creates an empty stack. -Note that since we haven't wired the function to our app, -the Lambda file does not appear in the output. +In this section we create a new |cdk| project using explicit command-line commands. +Be sure to navigate to the *hello-cdk* directory before you start. -.. code-block:: sh +.. _manual_initialize: + +Initializing the Project +------------------------ + +Create an empty project for the |cdk| app. + +.. tabs:: + + .. group-tab:: C# + + Create a new console application. + + .. code-block:: sh + + dotnet new console + + .. group-tab:: JavaScript + + Create an initial npm **package.json** file: + + .. code-block:: sh + + npm init -y # creates package.json + + Create a **.gitignore** file with the following content: + + .. code-block:: sh + + *.js + node_modules + + .. group-tab:: TypeScript + + Create an initial npm **package.json** file: + + .. code-block:: sh + + npm init -y # creates package.json + + Create a **.gitignore** file with the following content: + + .. code-block:: sh + + *.js + *.d.ts + node_modules + + Add the `build` and `watch` TypeScript commands to **package.json**: + + .. code-block:: json + + { + "scripts": { + "build": "tsc", + "watch": "tsc -w" + } + } + + Create a minimal **tsconfig.json**: + + .. code-block:: json + + { + "compilerOptions": { + "target": "es2018", + "module": "commonjs" + } + } + + Create a minimal **cdk.json** (this saves you from including `--app node bin/hello-cdk.js` in every `cdk` command): + + .. code-block:: json + + { + "app": "node bin/hello-cdk.js" + } + + .. group-tab:: Java + + Create a **.gitignore** file with the following content: + + .. code-block:: sh + + .classpath.txt + target + .classpath + .project + .idea + .settings + .vscode + *.iml + + Use your favorite IDE to create a Maven-based empty Java 8 project. + + Set the Java **source** and **target** to 1.8 in your **pom.xml** file: + + .. code-block:: xml + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.8 + 1.8 + + + + + +.. _manual_add_core: + +Adding the CDK Core as a Dependency +----------------------------------- + +Install the |cdk| core library (:py:mod:`@aws-cdk/cdk`) +This library includes the basic classes needed to write |cdk| stacks and apps. + +.. tabs:: + + .. group-tab:: C# + + Install the **Amazon.CDK NuGet** package: + + .. code-block:: sh + + dotnet add package Amazon.CDK + + .. group-tab:: JavaScript + + Install the **@aws-cdk/cdk** package: + + .. code-block:: sh + + npm install @aws-cdk/cdk + + .. group-tab:: TypeScript + + Install the **@aws-cdk/cdk** package: + + .. code-block:: sh + + npm install @aws-cdk/cdk + + .. group-tab:: Java + + Add the following to your project's `pom.xml` file: + + .. code-block:: xml + + + + software.amazon.awscdk + cdk + + + - npm run build - cdk synth +.. _manual_define_app: -.. _create_widgets_service: +Defining the |cdk| App +---------------------- -Step 3: Create Widgets Service -============================== +|cdk| apps are classes that extend the :py:class:`App <@aws-cdk/cdk.App>` +class. Create an empty **App**: -Add the |ABP|, |LAM|, and |S3| packages to our app. +.. tabs:: + + .. group-tab:: C# + + In **Program.cs** + + .. code-block:: c# + + using Amazon.CDK; + + namespace HelloCdk + { + class Program + { + static void Main(string[] args) + { + var myApp = new App(); + myApp.Run(); + } + } + } + + .. group-tab:: JavaScript + + Create the file **bin/hello-cdk.js**: + + .. code-block:: js + + const cdk = require('@aws-cdk/cdk'); + + class MyApp extends cdk.App { + constructor() { + super(); + } + } + + new MyApp().run(); + + .. group-tab:: TypeScript + + Create the file **bin/hello-cdk.ts**: + + .. code-block:: ts + + import cdk = require('@aws-cdk/cdk'); + import { HelloCdkStack } from '../lib/hello-cdkstack'; + + const app = new cdk.App(); + new HelloCdkStack(app, 'HelloCdkStack'); + app.run(); + + Create the file **lib/hello-cdkstack.ts**: + + .. code-block:: ts + + import cdk = require('@aws-cdk/cdk'); + + export class HelloCdkStack extends cdk.Stack { + constructor(parent: cdk.App, name: string, props?: cdk.StackProps) { + super(parent, name, props); + + // The code that defines your stack goes here + } + } + + .. group-tab:: Java + + In **src/main/java/com/acme/MyApp.java**: + + .. code-block:: java + + package com.acme; + + import software.amazon.awscdk.App; + + import java.util.Arrays; + + public class MyApp { + public static void main(final String argv[]) { + App app = new App(); + + app.run(); + } + } + +.. _manual_compile: + +Compiling the Code +------------------ + +If needed, compile the code: + +.. tabs:: + + .. group-tab:: C# + + Compile the code using your IDE or via the dotnet CLI: + + .. code-block:: sh + + dotnet build + + .. group-tab:: JavaScript + + No need to compile + + .. group-tab:: TypeScript + + To compile your program from **.ts** to **.js**: + + .. code-block:: sh + + npm run build + + You can also use the **watch** command to continuously compile your code + as it changes, so you don't have to invoke the compiler explicitly: + + .. code-block:: sh + + # run in another terminal session + npm run watch + + .. group-tab:: Java + + Compile your code using your IDE or via the command line via **mvn**: + + .. code-block:: sh + + mvn compile + +You have now created your first |cdk| app. + +.. _list_stacks: + +Listing the Stacks in the App +============================= + +Use the |cdk| toolkit's **ls** command to list the stacks in the app. .. code-block:: sh - npm install @aws-cdk/aws-apigateway @aws-cdk/aws-lambda @aws-cdk/aws-s3 + cdk ls -Create the directory *lib* at the same level as the *bin* and *resources* -directories. +The result is just the name of the stack: .. code-block:: sh - mkdir lib + HelloCdkStack -Create the following Typescript file, *widget_service.ts*, -in the *lib* directory. +.. note:: -.. code-block:: ts + There is a known issue on Windows with the |cdk| .NET environment. + Whenever you use a **cdk** command, + it issues a node warning similar to the following: - import cdk = require('@aws-cdk/cdk'); - import apigateway = require('@aws-cdk/aws-apigateway'); - import lambda = require('@aws-cdk/aws-lambda'); - import s3 = require('@aws-cdk/aws-s3'); + .. code-block:: sh - export class WidgetService extends cdk.Construct { - constructor(parent: cdk.Construct, name: string) { - super(parent, name); + (node:27508) UnhandledPromiseRejectionWarning: Unhandled promise rejection + (rejection id: 1): Error: EPIPE: broken pipe, write + (node:27508) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. + In the future, promise rejections that are not handled will terminate the + Node.js process with a non-zero exit code. - // Use S3 bucket to store our widgets - const bucket = new s3.Bucket(this, 'WidgetStore'); + You can safely ignore this warning. - // Create a handler that calls the function main - // in the source file widgets(.js) in the resources directory - // to handle requests through API Gateway - const handler = new lambda.Function(this, 'WidgetHandler', { - runtime: lambda.Runtime.NodeJS810, - code: lambda.Code.directory('resources'), - handler: 'widgets.main', - environment: { - BUCKET: bucket.bucketName // So runtime has the bucket name - } - }); +.. _define_stack: - bucket.grantReadWrite(handler.role); +Define a Stack +============== - // Create an API Gateway REST API - const api = new apigateway.RestApi(this, 'widgets-api', { - restApiName: 'Widget Service', - description: 'This service serves widgets.' - }); +Define a stack and add it to the app. - // Pass the request to the handler - const getWidgetsIntegration = new apigateway.LambdaIntegration(handler); +.. tabs:: - // Use the getWidgetsIntegration when there is a GET request - api.root.addMethod('GET', getWidgetsIntegration); // GET / - } - } + .. group-tab:: C# -Save it and make sure it builds and creates a (still empty) stack. + Create **MyStack.cs**: -.. code-block:: sh + .. code-block:: c# - npm run build - cdk synth + using Amazon.CDK; -.. _add_service: + namespace HelloCdk + { + public class MyStack: Stack + { + public MyStack(App parent, string name) : base(parent, name, null) + { + } + } + } -Step 4: Add the Service to the App -================================== + In **Program.cs**: -To add the service to our app, -add the following line of code after the existing **import** statement in -*my_widget_service.ts*. + .. code-block:: c# + :emphasize-lines: 10 -.. code-block:: ts + using Amazon.CDK; - import widget_service = require('../lib/widget_service'); + namespace HelloCdk + { + class Program + { + static void Main(string[] args) + { + var myApp = new App(); + new MyStack(myApp, "hello-cdk"); + myApp.Run(); + } + } + } -Add the following line of code at the end of the constructor in *my_widget_service.ts*. + .. group-tab:: JavaScript -.. code-block:: ts + In **index.js**: - new widget_service.WidgetService(this, 'Widgets'); + .. code-block:: js + :emphasize-lines: 3,4,5,6,7,13 -Make sure it builds and creates a stack -(we don't show the stack as it's almost 300 lines). + const cdk = require('@aws-cdk/cdk'); -.. code-block:: sh + class MyStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + } + } + + class MyApp extends cdk.App { + constructor(argv) { + super(argv); + + new MyStack(this, 'hello-cdk'); + } + } + + new MyApp().run(); + + .. group-tab:: TypeScript + + Nothing to do. + + .. group-tab:: Java + + In **src/main/java/com/acme/MyStack.java**: + + .. code-block:: java + + package com.acme; + + import software.amazon.awscdk.App; + import software.amazon.awscdk.Stack; + import software.amazon.awscdk.StackProps; + + public class MyStack extends Stack { + public MyStack(final App parent, final String name) { + this(parent, name, null); + } + + public MyStack(final App parent, final String name, final StackProps props) { + super(parent, name, props); + } + } - npm run build - cdk synth + In **src/main/java/com/acme/MyApp.java**: -.. _deploy_and_test: + .. code-block:: java + :emphasize-lines: 12 -Step 5: Deploy and Test the App -=============================== + package com.acme; -Before you can deploy your first |cdk| app, -you must bootstrap your deployment, -which creates some AWS infracture that the |cdk| -needs. -See the **bootstrap** section of the :doc:`tools` topic for details. + import software.amazon.awscdk.App; + import java.util.Arrays; + + public class MyApp { + public static void main(final String argv[]) { + App app = new App(); + + new MyStack(app, "hello-cdk"); + + app.run(); + } + } + +The initializer signature of **cdk.Stack** includes the arguments: **parent**, +**id**, and **props**. This is the signature for every class in the |cdk| +framework. These classes are called **"constructs"** and they are composed +together into a tree: + +* **parent** represents the parent construct. By specifying the parent construct + upon initialization, constructs can obtain contextual information when they + are initialized. For example, the region a stack is deployed to can be + obtained via a call to :py:meth:`Stack.find(this).requireRegion() <@aws-cdk/cdk.Stack.requireRegion>`. + See :doc:`context` for more information. +* **id** is a string that locally identifies this construct within the tree. + Constructs must have a unique ID amongst their siblings. +* **props** is the set of initialization properties for this construct. + +Compile your program: + +.. tabs:: + + .. group-tab:: C# + + We configured *cdk.json* to run `dotnet run`, which + restores dependencies, builds, and runs your application, + run `cdk`. + + .. code-block:: sh + + cdk + + .. group-tab:: JavaScript + + Nothing to compile. + + .. group-tab:: TypeScript + + .. code-block:: sh + + npm run build + + .. group-tab:: Java + + .. code-block:: sh + + mvn compile + +.. _define_bucket: + +Define an |S3| Bucket +===================== + +Now, what can we do with this app? Nothing yet. Our stack is still empty, so +there's nothing to deploy. + +Let's define an |S3| bucket. + +Install the **@aws-cdk/aws-s3** package: + +.. tabs:: + + .. group-tab:: C# + + .. code-block:: sh + + dotnet add package Amazon.CDK.AWS.S3 + + .. group-tab:: JavaScript + + .. code-block:: sh + + npm install @aws-cdk/aws-s3 + + .. group-tab:: TypeScript + + .. code-block:: sh + + npm install @aws-cdk/aws-s3 + + .. group-tab:: Java + + Edit your **pom.xml** file: + + .. code-block:: sh + + + software.amazon.awscdk + s3 + + + +Next, define an |S3| bucket in the stack. |S3| buckets are represented by +the :py:class:`Bucket <@aws-cdk/aws-s3.Bucket>` class: + +.. tabs:: + + .. group-tab:: C# + + Create **MyStack.cs**: + + .. code-block:: c# + :emphasize-lines: 2,10,11,12,13 + + using Amazon.CDK; + using Amazon.CDK.AWS.S3; + + namespace HelloCdk + { + public class MyStack : Stack + { + public MyStack(App parent, string name) : base(parent, name, null) + { + new Bucket(this, "MyFirstBucket", new BucketProps + { + Versioned = true + }); + } + } + } + + .. group-tab:: JavaScript + + In **index.js**: + + .. code-block:: js + :emphasize-lines: 2,8,9,10 + + const cdk = require('@aws-cdk/cdk'); + const s3 = require('@aws-cdk/aws-s3'); + + class MyStack extends cdk.Stack { + constructor(parent, id, props) { + super(parent, id, props); + + new s3.Bucket(this, 'MyFirstBucket', { + versioned: true + }); + } + } + + .. group-tab:: TypeScript + + In **lib/**: + + .. code-block:: ts + :emphasize-lines: 2,8,9,10 + + import cdk = require('@aws-cdk/cdk'); + import s3 = require('@aws-cdk/aws-s3'); + + export class HelloCdkStack extends cdk.Stack { + constructor(parent: cdk.App, id: string, props?: cdk.StackProps) { + super(parent, id, props); + + new s3.Bucket(this, 'MyFirstBucket', { + versioned: true + }); + } + } + + .. group-tab:: Java + + In **src/main/java/com/acme/MyStack.java**: + + .. code-block:: java + :emphasize-lines: 6,7,13,14,15 + + package com.acme; + + import software.amazon.awscdk.App; + import software.amazon.awscdk.Stack; + import software.amazon.awscdk.StackProps; + import software.amazon.awscdk.services.s3.Bucket; + import software.amazon.awscdk.services.s3.BucketProps; + + public class MyStack extends Stack { + public MyStack(final App parent, final String name) { + this(parent, name, null); + } + + public MyStack(final App parent, final String name, final StackProps props) { + super(parent, name, props); + + new Bucket(this, "MyFirstBucket", BucketProps.builder() + .withVersioned(true) + .build()); + } + } + +A few things to notice: + +* :py:class:`Bucket <@aws-cdk/aws-s3.Bucket>` is a construct. + This means it's initialization signature has **parent**, **id**, and **props**. + In this case, the bucket is an immediate child of **MyStack**. +* ``MyFirstBucket`` is the **logical id** of the bucket construct, **not** the physical name of the + S3 bucket. The logical ID is used to uniquely identify resources in your stack + across deployments. See :doc:`logical-ids` for more details on how to work + with logical IDs. To specify a physical name for your bucket, you can set the + :py:meth:`bucketName <@aws-cdk/aws-s3.BucketProps.bucketName>` property when + you define your bucket. +* Since the bucket's :py:meth:`versioned <@aws-cdk/aws-s3.BucketProps.versioned>` + property is :code:`true`, `versioning `_ + is enabled on the bucket. + +Compile your program: + +.. tabs:: + + .. group-tab:: C# + + We configured *cdk.json* to run `dotnet run`, which + restores dependencies, builds, and runs your application, + run `cdk`. + + .. group-tab:: JavaScript + + Nothing to compile. + + .. group-tab:: TypeScript + + .. code-block:: sh + + npm run build + + .. group-tab:: Java + + .. code-block:: sh + + mvn compile + +.. _synthesize_template: + +Synthesize an |CFN| Template +============================ + +Synthesize a |cfn| template for the stack: .. code-block:: sh - cdk bootstrap + cdk synth HelloCdkStack + +.. note:: Since the |cdk| app only contains a single stack, you can omit :code:`HelloCdkStack`. + +This command executes the |cdk| app and synthesize an |CFN| template for the +**HelloCdkStack** stack. +You should see something similar to the following, +where VERSION is the version of the |cdk|. -Run the following command to deploy your app. +.. code-block:: yaml + + Resources: + MyFirstBucketB8884501: + Type: AWS::S3::Bucket + Properties: + VersioningConfiguration: + Status: Enabled + Metadata: + aws:cdk:path: HelloCdkStack/MyFirstBucket/Resource + CDKMetadata: + Type: AWS::CDK::Metadata + Properties: + Modules: "@aws-cdk/aws-codepipeline-api=VERSION,@aws-cdk/aws-events=VERSION,@aws-c\ + dk/aws-iam=VERSION,@aws-cdk/aws-kms=VERSION,@aws-cdk/aws-s3=VERSION,@aws-c\ + dk/aws-s3-notifications=VERSION,@aws-cdk/cdk=VERSION,@aws-cdk/cx-api=VERSION\ + .0,hello-cdk=0.1.0" + +You can see that the stack contains an **AWS::S3::Bucket** resource with the desired +versioning configuration. + +.. note:: + + The **AWS::CDK::Metadata** resource was automatically added to your template + by the toolkit. This allows us to learn which libraries were used in your + stack. See :ref:`version_reporting` for more details and how to + :ref:`opt-out `. + +.. _deploy_stack: + +Deploying the Stack +=================== + +Use **cdk deploy** to deploy the stack: .. code-block:: sh cdk deploy -If the deployment is successfull, -save the URL for your server, which appears in the last line in the window, -where GUID is an alpha-numeric GUID and REGION is your region. +The **deploy** command synthesizes an |CFN| template from the stack +and then invokes the |CFN| create/update API to deploy it into your AWS +account. The command displays information as it progresses. + +.. _modify_cde: + +Modifying the Code +================== + +Configure the bucket to use KMS managed encryption: + +.. tabs:: + + .. group-tab:: C# + + .. code-block:: c# + :emphasize-lines: 4 + + new Bucket(this, "MyFirstBucket", new BucketProps + { + Versioned = true, + Encryption = BucketEncryption.KmsManaged + }); + + .. group-tab:: JavaScript + + .. code-block:: js + :emphasize-lines: 3 + + new s3.Bucket(this, 'MyFirstBucket', { + versioned: true, + encryption: s3.BucketEncryption.KmsManaged + }); + + .. group-tab:: TypeScript + + .. code-block:: ts + :emphasize-lines: 3 + + new s3.Bucket(this, 'MyFirstBucket', { + versioned: true, + encryption: s3.BucketEncryption.KmsManaged + }); + + .. group-tab:: Java + + .. code-block:: java + :emphasize-lines: 3 + + new Bucket(this, "MyFirstBucket", BucketProps.builder() + .withVersioned(true) + .withEncryption(BucketEncryption.KmsManaged) + .build()); + +Compile the program: + +.. tabs:: + + .. group-tab:: C# + + We configured *cdk.json* to run `dotnet run`, which + restores dependencies, builds, and runs your application, + run `cdk`. + + .. group-tab:: JavaScript + + Nothing to compile. + + .. group-tab:: TypeScript + + .. code-block:: sh + + npm run build + + .. group-tab:: Java + + .. code-block:: sh + + mvn compile + +.. _prepare_deployment: + +Preparing for Deployment +======================== + +Before you deploy the updated stack, use the ``cdk diff`` command to evaluate +the difference between the |cdk| app and the deployed stack: .. code-block:: sh - https://GUID.execute-REGION.amazonaws.com/prod/ + cdk diff -You can test your app by getting the list of widgets (currently empty) by navigating to this URL in a -browser or use the following **curl** command. +The toolkit queries your AWS account for the current |CFN| template for the +**hello-cdk** stack, and compares the result with the template synthesized from the app. +The output should look like the following: .. code-block:: sh - curl -X GET 'https://GUID.execute-REGION.amazonaws.com/prod' + [~] 🛠 Updating MyFirstBucketB8884501 (type: AWS::S3::Bucket) + └─ [+] .BucketEncryption: + └─ New value: {"ServerSideEncryptionConfiguration":[{"ServerSideEncryptionByDefault":{"SSEAlgorithm":"aws:kms"}}]} + +As you can see, the diff indicates that the +**ServerSideEncryptionConfiguration** property of the bucket is now set to +enable server-side encryption. -You can also open the |console|, -navigate to the |ABP| service, -find **Widget Service** in the list. -Select **GET** and **Test** to test the function. -Since we haven't stored any widgets yet, the output should be similar to the following -(there may be some slight differences in whitespace and quotation marks). +You can also see that the bucket is not going to be replaced but rather updated +("**Updating MyFirstBucketB8884501**"). + +Run **cdk deploy** to update the stack: .. code-block:: sh - { "widgets": [] } - -.. _adding_functions: - -Step 6: Add the Individual Widget Functions -=========================================== - -The next step is to create |LAM| functions to create, show, and delete -individual widgets. -Replace the existing **exports.main** function in *widgets.js* with the following code. - -.. code-block:: js - - exports.main = async function(event, context) { - try { - var method = event.httpMethod; - // Get name, if present - var widgetName = event.path.startsWith('/') ? event.path.substring(1) : event.path; - - if (method === "GET") { - // GET / to get the names of all widgets - if (event.path === "/") { - const data = await S3.listObjectsV2({ Bucket: bucketName }).promise(); - var body = { - widgets: data.Contents.map(function(e) { return e.Key }) - }; - return { - statusCode: 200, - headers: {}, - body: JSON.stringify(body) - }; - } - - if (widgetName) { - // GET /name to get info on widget name - const data = await S3.getObject({ Bucket: bucketName, Key: widgetName}).promise(); - var body = data.Body.toString('utf-8'); - - return { - statusCode: 200, - headers: {}, - body: JSON.stringify(body) - }; - } - } - - if (method === "POST") { - // POST /name - // Return error if we do not have a name - if (!widgetName) { - return { - statusCode: 400, - headers: {}, - body: "Widget name missing" - }; - } - - // Create some dummy data to populate object - const now = new Date(); - var data = widgetName + " created: " + now; - - var base64data = new Buffer(data, 'binary'); - - await S3.putObject({ - Bucket: bucketName, - Key: widgetName, - Body: base64data, - ContentType: 'application/json' - }).promise(); - - return { - statusCode: 200, - headers: {}, - body: JSON.stringify(event.widgets) - }; - } - - if (method === "DELETE") { - // DELETE /name - // Return an error if we do not have a name - if (!widgetName) { - return { - statusCode: 400, - headers: {}, - body: "Widget name missing" - }; - } - - await S3.deleteObject({ - Bucket: bucketName, Key: widgetName - }).promise(); - - return { - statusCode: 200, - headers: {}, - body: "Successfully deleted widget " + widgetName - }; - } - - // We got something besides a GET, POST, or DELETE - return { - statusCode: 400, - headers: {}, - body: "We only accept GET, POST, and DELETE, not " + method - }; - } catch(error) { - var body = error.stack || JSON.stringify(error, null, 2); - return { - statusCode: 400, - headers: {}, - body: body - } - } - } - -Wire these functions up to our |ABP| code in *widget_service.ts* -by adding the following code at the end of the constructor. - -.. code-block:: ts - - const widget = api.root.addResource('{name}'); - - // Add new widget to bucket with: POST /{name} - const postWidgetIntegration = new apigateway.LambdaIntegration(handler); - - // Get a specific widget from bucket with: GET /{name} - const getWidgetIntegration = new apigateway.LambdaIntegration(handler); - - // Remove a specific widget from the bucket with: DELETE /{name} - const deleteWidgetIntegration = new apigateway.LambdaIntegration(handler); - - widget.addMethod('POST', postWidgetIntegration); // POST /{name} - widget.addMethod('GET', getWidgetIntegration); // GET /{name} - widget.addMethod('DELETE', deleteWidgetIntegration); // DELETE /{name} - -Save, build, and deploy the app. - -Now we should be able to store, show, or delete an individual widget. -Use the following **curl** commands to list the widgets, -create the widget *dummy*, -list all of the widgets, -show the contents of *dummy* (it should show today's date), -and delete *dummy*, -and again show the list of widgets. + cdk deploy + +The toolkit updates the bucket configuration to enable server-side KMS +encryption for the bucket: .. code-block:: sh - curl -X GET 'https://GUID.execute-REGION.amazonaws.com/prod' - curl -X POST 'https://GUID.execute-REGION.amazonaws.com/prod/dummy' - curl -X GET 'https://GUID.execute-REGION.amazonaws.com/prod' - curl -X GET 'https://GUID.execute-REGION.amazonaws.com/prod/dummy' - curl -X DELETE 'https://GUID.execute-REGION.amazonaws.com/prod/dummy' - curl -X GET 'https://GUID.execute-REGION.amazonaws.com/prod' + ⏳ Starting deployment of stack hello-cdk... + [0/2] UPDATE_IN_PROGRESS [AWS::S3::Bucket] MyFirstBucketB8884501 + [1/2] UPDATE_COMPLETE [AWS::S3::Bucket] MyFirstBucketB8884501 + [1/2] UPDATE_COMPLETE_CLEANUP_IN_PROGRESS [AWS::CloudFormation::Stack] hello-cdk + [2/2] UPDATE_COMPLETE [AWS::CloudFormation::Stack] hello-cdk + ✅ Deployment of stack hello-cdk completed successfully + +.. _whats_next: + +What Next? +========== + + * Learn more about :doc:`CDK Concepts ` + * Check out the `examples directory `_ in your GitHub repository + * Learn about the rich APIs offered by the :doc:`AWS Construct Library ` + * Work directly with CloudFormation using the :doc:`AWS CloudFormation Library ` + * Come talk to us on `Gitter `_ -You can also use the |ABP| console to test these functions. -You'll have to set the **name** entry to the name of an widget, -such as **dummy**.