AWS re:Invent 2020: Build your first AWS CloudFormation resource provider

AWS re:Invent 2020: Build your first AWS CloudFormation resource provider


AWS re:Invent 2020: Build your first AWS CloudFormation resource provider

Last year, AWS announced the ability for you to define your own AWS CloudFormation resource types. Resource types allow you to define custom infrastructure provisioning logic and encapsulate it in a declarative specification. In this session, learn how to build a custom resource type and publish it so that others can reuse it as well.

Learn more about re:Invent 2020 at http://bit.ly/3c4NSdY

Subscribe:
More AWS videos http://bit.ly/2O3zS75
More AWS events videos http://bit.ly/316g9t4

#AWS #AWSEvents


Content

2.159 -> hi my name is craig lefkowitz i'm a
4 -> senior developer advocate with aws
6.24 -> cloudformation
7.12 -> and i'm going to talk about building
8.639 -> your first aws cloud formation resource
10.96 -> provider
13.04 -> we'll start with what resource providers
15.28 -> are and when you use them with cloud
17.039 -> formation
18 -> we'll talk about the building blocks and
20.08 -> tools that you'll use with
21.6 -> resource providers lastly we'll walk
23.84 -> through a typical development
25.519 -> and operational pattern and then end
27.519 -> with a demo
30.24 -> so let's start with the typical pattern
32.079 -> for creating resources with cloud
33.76 -> formation
34.719 -> you start with authoring code that's
36.239 -> written in yaml or json
38.16 -> that code is then uploaded using your
39.92 -> browser or in more
41.2 -> modern devops approaches you could be
43.44 -> publishing code to a repository as part
45.76 -> of a ci cd pipeline
47.92 -> the code is then executed and resources
50.16 -> are deployed
52.8 -> so let's focus on some coding scenarios
55.28 -> cloudformation templates are written in
57.039 -> yaml
57.68 -> or json and they come with a core set of
59.84 -> functionality
61.44 -> parameters resources mappings and
63.84 -> outputs
64.799 -> you also have the ability to author
66.64 -> macros in order to provide abstractions
68.96 -> and shortcuts
70.08 -> the serverless application model or sam
72.4 -> is a great example of this
74.4 -> you can also provision resources in
75.92 -> cloud information using popular coding
77.759 -> languages such as
78.72 -> python or go using the aws cloud
81.68 -> development kit or cdk
84.32 -> and lastly and we're going to focus on
86.56 -> in this session
87.439 -> are resource types which is an extension
90.159 -> to cloudformation that allows management
92 -> of third-party
93.92 -> resources such as new relic alerts or
96.479 -> dynatrace agents
97.759 -> for example or really any resource that
100.24 -> you'd like to manage
101.6 -> if there's something that you want to
102.72 -> manage with cloud formation and the
104.399 -> native aws type doesn't exist
106.799 -> you should be looking at resource types
110.799 -> so resource types are cloud formation
112.56 -> resources that can be authored by anyone
114.96 -> and then
115.759 -> used in cloud formation templates just
118.159 -> like the service teams here at aws
120.32 -> author and ec2 instance resource or an
123.52 -> s3 bucket resource
125.119 -> you can do the same thing resource types
127.6 -> that you author are first class objects
129.759 -> which means that to the cloud formation
131.52 -> engine
132.16 -> a resource type that you author and the
134.239 -> native aws resource is almost
136.4 -> indistinguishable
137.599 -> to the cloud formation engine and that's
140.08 -> because we're all using the same
141.28 -> framework
142.239 -> this allows tighter integration with
143.84 -> cloudformation features
145.36 -> such as drift detection and resource
147.04 -> import as well as other aws services
149.84 -> such as aws config
152.16 -> resource types have some distinct
153.92 -> features such as the registry
156.16 -> which is a centralized repository where
158.319 -> resource types are stored
159.92 -> as well as other technical details that
161.84 -> we'll get to in a bit
165.68 -> so you may be familiar with custom
167.28 -> resources which is a feature we
168.879 -> introduced in 2015
170.8 -> that enables cloud information to manage
172.64 -> non-native aws resources
175.04 -> resource providers work a little bit
176.8 -> differently
178.4 -> so as an author of a resource type
180.159 -> you're going to start with a
182.08 -> writing a schema file that defines your
184.56 -> resource
185.76 -> there are um inputs and outputs
189.44 -> in that schema file there's some
191.599 -> metadata such as im permissions
194.08 -> uh you also offer handler code that
196.319 -> handles five cloud formation
197.76 -> actions which is create update delete
200.64 -> read and list
202.8 -> the code and the schema is packaged and
205.2 -> submitted to the cloudformation registry
208.48 -> once in the registry it's then available
210.56 -> to use in a cloudformation template
212.879 -> by any consumer in your organization to
215.2 -> provision and manage the resources that
216.879 -> you define in your code
219.2 -> so notable differences from custom
220.799 -> resources are that the handler code is
223.04 -> executed in the confirmation service
225.36 -> account
226 -> you no longer have to manage the lambda
227.76 -> function that
229.04 -> backs your resource authoring a resource
231.76 -> type starts with defining a schema
234 -> which enforces strong typing this allows
236.159 -> for greater integration with other aws
238.319 -> services
239.439 -> resource types have configurable
241.12 -> timeouts providing greater control on
243.12 -> your resources lifecycle
245.2 -> we provide a command line tool that
247.36 -> accelerates development by providing
249.12 -> scaffolding testing and
250.799 -> provisioning tools and resource types
253.28 -> use the cloud formation registry
254.879 -> which is a centralized version
256.16 -> repository that allows you to easily
258.4 -> share your resource
259.519 -> across templates
263.6 -> there are three major components of a
264.96 -> resource type first is the registry
267.36 -> which is a version repository where
269.28 -> resource types are stored
271.84 -> second is the confirmation cli which is
274.08 -> an open source command line tool
276.08 -> that helps with the development of
277.44 -> resource types and registers them for
279.759 -> use with confirmation
281.199 -> it includes commands to enable each step
283.199 -> of creating your resource types
284.88 -> and we'll get into that uh detail into a
287.68 -> little bit later in this presentation
289.68 -> up on the screen i have a qr code that
291.84 -> links to the cloudformation cli github
294.4 -> repository that you can
296.08 -> view later the cloudformation cli was
299.84 -> designed to be language agnostic through
301.44 -> the use of a core library
303.44 -> today the cloud formation cli officially
305.68 -> supports three language
307.199 -> plugins java python and go but it can be
310.24 -> extended to use any language through the
312 -> use of the plugin system
313.84 -> more detail is available in our github
315.759 -> repository
319.759 -> so as i mentioned in the previous slide
321.6 -> once you author a resource type
323.52 -> you submit them to the confirmation
325.039 -> registry the registry is where resource
327.28 -> types are stored
328.24 -> both resources that you develop as well
330.479 -> as the native aws resource types
333.44 -> native aws resource types that are
335.44 -> authored by aws
336.96 -> are labeled public resource types that
339.52 -> you develop are labeled
340.96 -> private in the console displayed
344.16 -> i've filtered by private types in the
345.759 -> drop down so i see the private types
347.68 -> that have been registered to my account
349.68 -> if i click one of those types i can see
351.28 -> additional information on that type
354.56 -> such as the schema and the version
357.6 -> remember that the registry is a
359.039 -> versioned repository
360.72 -> detailed information on your resource
362.319 -> type can be viewed in the console like
363.84 -> you see here
364.8 -> as well as through the api
368.319 -> so let's talk a little bit about the
369.52 -> cloud formation cli which is an open
371.52 -> source tool that provides a
373.28 -> consistent way to model and provision
375.28 -> resource types through cloud formation
377.6 -> it includes commands to enable each step
379.6 -> of creating your extensions
381.36 -> it's installed through pi pi and
383.28 -> provides several commands that assist
384.8 -> with
385.36 -> developing testing and submitting
387.12 -> resource types
388.88 -> it also has commands to initialize the
390.88 -> scaffolding for a new project
393.6 -> run contract tests and submit your
396.319 -> resource type to the registry
400 -> so let's run through a typical
401.28 -> development pattern
403.12 -> the first thing you're going to do after
404.8 -> creating a blank directory
406.56 -> for development is to run the cfn init
408.72 -> command
409.919 -> this command creates the scaffolding
412.16 -> code and directory structure for
414.08 -> a resource type project once the project
417.44 -> has been initialized
418.88 -> you'll define your model which is a json
420.88 -> file in the root of your directory named
422.639 -> after the name of your resource type
424.72 -> this is also called the schema you then
427.84 -> author your handler code
429.36 -> which is located in a directory specific
431.199 -> to the language you're developing in
432.96 -> this code contains logic for the five
434.56 -> cloud formation actions which are create
436.88 -> update delete read and list we'll talk
439.759 -> about those actions in more detail in a
441.44 -> bit
442.639 -> so after authoring your handler logic
444.72 -> you'll want to run cfn
446.08 -> generate to update the auto-generated
448.24 -> files in your project
449.68 -> you'll build your code as you normally
451.199 -> do depending on the language you're
452.56 -> developing in
453.759 -> and after your code is built run cfn
456 -> tests to perform contract tests against
457.84 -> your handler code
460 -> once you're satisfied that your code
461.44 -> pass passes you'll package and submit
463.68 -> your code to the cloud formation
464.8 -> registry using the cfn submit command
467.44 -> note that i've used the set default
468.96 -> switch which sets the version i'm
470.639 -> submitting as the default version
472.8 -> remember that the cloud formation
474.4 -> registry is a version repository and
476.479 -> only one version can be active at any
478.319 -> given time
479.52 -> the set default command sets this
481.12 -> version as the active version
483.039 -> and this is the version that any future
484.639 -> confirmation templates will use
487.199 -> then test your code by sub submitting
489.68 -> your
490.4 -> template that references your resource
491.919 -> type fix any issues that you encounter
494.56 -> and then repeat the process
498.16 -> so one of the first things you'll do
499.28 -> when developing a resource type is model
501.039 -> your resource by offering a resource
503.039 -> schema
503.759 -> this is that json file in the root of
505.44 -> your project's directory that's named
506.879 -> after your resource
508.319 -> we're looking at an example of a
509.599 -> resource named aws utility cloud
511.68 -> formation command runner
513.44 -> the first section is the properties
515.919 -> which define the inputs
517.519 -> in this example we see a single input
519.279 -> named command which is of type string
522.399 -> next you'll define the outputs of your
523.839 -> resource type which are the attributes
525.6 -> that a user of your resource type would
527.279 -> access through the get at intrinsic
528.8 -> function
529.76 -> these are defined in the read-only
531.12 -> properties section here we see that
533.04 -> there are two attributes
534.24 -> one named output and the other id
537.68 -> moving on to the handler section here
539.68 -> you're going to list the handlers that
540.959 -> your resource type will process
542.72 -> you don't have to implement all of the
544.08 -> confirmation actions for example
546.08 -> you can specify that your resource
548.08 -> provider handles only create read and
550.08 -> delete
550.64 -> but not update in this case when
552.88 -> confirmation attempts to perform an
554.56 -> update on your resource it will replace
556.48 -> your resource by creating a new resource
559.04 -> and deleting the existing one you'll
561.839 -> also define the im permissions each
564 -> handler requires
565.279 -> in this example the create handler
567.2 -> requires the ec2 described subnet's
569.279 -> permission
570.16 -> by defining the permissions your
571.6 -> resource handler requires
573.2 -> you inform users of your resource the
575.12 -> minimum set of permissions needed
576.8 -> to implement your resource
580.32 -> so let's take a deeper look at those
581.68 -> permissions in the resource type schema
584.32 -> in each confirmation action that your
585.92 -> resource type handles
587.36 -> you should specify the impermissions
589.04 -> that it needs to perform that action
590.959 -> this provides users of your resource
592.48 -> type to definitively know
594 -> the exact permissions your resource type
595.92 -> requires
597.279 -> using the cfn generate command you you
599.839 -> can create a
600.8 -> cloudformation template that provisions
602.56 -> an im role with the permissions defined
604.72 -> in your resource schema
606.64 -> the cfn generate command will create a
608.48 -> file called resource role dot yaml
610.8 -> and the root of your project that
612.079 -> provisions that i am role
614.72 -> this role can be used to assign an
616.48 -> execution role to your resource
618.56 -> if assigned cloudformation will use the
620.48 -> execution role to provision
622.079 -> any aws resources in your resource type
625.12 -> otherwise cloudformation will use the
626.72 -> permissions of the user calling the
628.72 -> resource type
630.079 -> assigning a execution role can be a
632.32 -> handy way to allow
633.36 -> operators to use your resource type
635.12 -> without having to directly grant them
637.279 -> an im role that would otherwise be
639.68 -> overly permissive
641.519 -> for example let's say that your resource
643.6 -> type requires that all
645.12 -> i am permissions for ec2 need to be
648 -> present
648.8 -> so you can assign an execution role to
650.56 -> the resource type that grants that
652 -> permission
653.04 -> a user that uses that uses your resource
655.36 -> type in a template
656.8 -> wouldn't need any ec2 permissions for it
658.88 -> to work
661.76 -> so let's talk a little bit about the
663.12 -> handlers there are five actions that
665.279 -> cloudformation can send to your resource
666.959 -> type to handle
668.079 -> you're likely familiar with three of
669.44 -> them namely create
671.68 -> update and delete however there are two
674.32 -> actions that you may not be
675.68 -> read and list the read action is used
678.8 -> for getting attributes of your resource
680.959 -> for example when a user calls the get
682.72 -> intrinsic function it's also used if a
685.12 -> user wants to import
686.64 -> an existing resource into their
688 -> confirmation template or it can be used
689.839 -> for drift detection
691.279 -> in this case cloudformation will request
693.12 -> the properties of the existing resource
694.72 -> in order to perform those actions
697.44 -> list is an action that will be used in
698.8 -> future use cases one such use case is
700.959 -> when a user or system
702.32 -> wants to list multiple existing
703.839 -> resources that can be used for a bulk
705.519 -> resource import operation
710.56 -> so there are some things that you want
711.68 -> to consider when developing your
713.04 -> resources
714.24 -> is that each handler has a single entry
716.079 -> point that doesn't mean that the code
718.399 -> for your handler has to be implemented
720.24 -> entirely in that entry point
721.92 -> and can be dispatched to another
723.36 -> function or class that's located in a
724.88 -> separate file
726.72 -> handlers must not leak resources keep
728.959 -> track of the resources
730 -> that you create so that when a delete
731.839 -> action is passed to your resource type
733.68 -> it will delete all the resources you've
735.839 -> provisioned
738.24 -> a handler must return a progress event
739.92 -> within 60 seconds or it's going to be
741.519 -> marked as failed and rolled back
743.76 -> so what if you need more time you can
745.76 -> use callbacks
746.8 -> which we'll cover in a bit
750.72 -> so let's first talk about what a
751.92 -> progress event is before getting to call
753.839 -> backs
754.639 -> a progress event is a json object that's
756.72 -> always returned from your handler
759.2 -> the progress event describes the status
761.839 -> of your resource which is either success
764.079 -> failed or in progress if the creation of
767.279 -> your resource is successful
768.959 -> set the operation status to success if
771.68 -> the
772.32 -> you set the status to success
773.839 -> cloudformation will mark the resource as
775.76 -> successfully provisioned
777.12 -> and will continue processing other
778.639 -> resources in the template
781.44 -> in the event that you encounter an error
783.6 -> you'll set operation status to failed
785.68 -> and set the appropriate handler error
787.44 -> code in this case
788.72 -> cloudformation will mark the resource as
790.48 -> failed and will roll back
792.72 -> remember to always set the message to
794.399 -> something descriptive and actionable
796.399 -> so that the user has visibility into
798.24 -> what's happening
801.44 -> let's get into those callbacks this is
804.079 -> what you're going to use if your code
805.36 -> needs more than 60 seconds to provision
807.12 -> your resource
808.48 -> here we see handler code returning a
810.079 -> progress event with an in-progress
811.839 -> operation status the progress event is
814.32 -> set with a callback delay of 300 seconds
816.399 -> and a callback context
817.92 -> which is any state that you'd like
819.36 -> returned when cloud formation reinvokes
821.279 -> your handler
822.32 -> remember your code is being executed in
824.079 -> a lambda function and is stateless
826.399 -> the callback context allows state to be
828.16 -> passed back in 300 seconds
830.56 -> cloudformation will call your resort
832.16 -> handler code again along with your
834.16 -> callback
835.04 -> context object your handler code
837.519 -> executes its logic
838.639 -> and if it needs more time it can again
840.639 -> return the progress event
842.24 -> and an in-progress operation status
845.12 -> cloudformation will continue this cycle
847.04 -> up to the limit set in the timeout in
848.8 -> minutes property
850.24 -> that's in your schema file up to a max
852.48 -> of 36 hours
854.16 -> if the timeout in minutes property is
856 -> not defined it defaults to two hours
859.6 -> when your handler code has reached a
861.04 -> terminal state you'll return an
862.8 -> operation status of success
864.8 -> or a failure signaling to confirmation
866.959 -> that your resource has completed
868.48 -> and what it should do next either mark
870.24 -> the resource as complete
871.6 -> or roll back so let's switch gears
875.6 -> here and we'll talk about some
876.8 -> operational patterns
880.079 -> if you encounter an error during
881.519 -> execution of your handler code
883.279 -> you should return a progress event with
884.959 -> an operation status value of failed
887.199 -> a handler error code and a message
889.199 -> that's passed back to the user in the
890.56 -> form of a status reason
892.32 -> in this example we inform the user that
894.16 -> we encountered a 400 bad request during
896.639 -> execution
897.6 -> and you can see uh from the gui and the
900.399 -> status reason column
901.6 -> that that 400 bad request message is
903.68 -> displayed to the user
907.04 -> you can also send logs to cloudwatch the
909.279 -> law group is named after your resource
910.88 -> type using the following format
912.8 -> namespace service name resource name
915.04 -> logs
916.72 -> and here we have an example on the
918.079 -> screen with an aws utility
920.24 -> cloudformation command runner
921.839 -> resource that's in the law group
926.56 -> if you use the cfn submit tool to submit
928.639 -> your resource type
929.68 -> logging is automatically enabled if you
932 -> use the aws cli to register your type
934.639 -> you must use the logging config option
936.399 -> to turn on logging
938.24 -> and those are the basics you'll need to
939.519 -> create your first resource provider
942.399 -> before getting into the demo i'd like to
944.32 -> call out some notable examples of
945.839 -> resource providers being used today
948.16 -> as i said before the service teams here
949.839 -> at aws are authoring their resources
952.56 -> resource providers using the same
954.079 -> resource provider framework we're
955.44 -> talking about today
956.8 -> the aws quick starts team has a resource
959.04 -> provider to manage helm
960.48 -> on eks as well as partners such as
963.6 -> mongodb
964.399 -> new relic and dynatrace to name a few
966.8 -> and with that
967.68 -> let's get into the demo i'm going to
970.32 -> show you
970.8 -> a resource type that was written by aws
974.32 -> support called command runner
976.32 -> this resource type takes a batch command
978.24 -> as input runs it
980.16 -> and stores the output as an attribute
981.759 -> that can be referenced in your template
983.839 -> this resource type has a number of use
986.24 -> cases for example
987.759 -> if you wanted to perform some complex
989.36 -> math operations
990.88 -> or perform advanced string manipulation
993.839 -> you can do that pretty simply by writing
995.6 -> the appropriate bash commands
997.759 -> and then you could reference the output
999.199 -> of those bash commands in your template
1001.92 -> we wrote a blog about it which is here
1004.079 -> on the screen it has a
1005.68 -> nice diagram that shows how this all
1007.6 -> works it also has an example where
1010 -> we calculate the number of iops for an
1012.079 -> ebs volume
1013.279 -> based on its size i have a qr code up on
1016.48 -> the screen so that you can
1018 -> read it later so if we look at the
1021.04 -> diagram of how this works under the hood
1024.24 -> uh we see that the command runner
1026 -> resource type spins up in ec2 instance
1029.12 -> it runs the bash command on the instance
1031.679 -> the output is stored
1033.199 -> and then the instance is terminated so
1036.319 -> if you remember from the um the slides
1039.36 -> um that i talked about um resource types
1043.039 -> must return their status within 60
1044.799 -> seconds
1045.36 -> or cloud information is going to mark
1047.439 -> that resource as
1048.559 -> timed out the stack could then be rolled
1051.76 -> back
1053.28 -> but um spinning up an ec2 instance
1055.76 -> usually takes longer than the
1057.679 -> 60-second window this is a case where we
1060.16 -> use callbacks to get around that
1062.16 -> 60-second limit so let's take a look at
1064.64 -> the code which is
1065.919 -> available on github the link to the
1068.32 -> github repository is um in the blog
1073.44 -> so i'm going to grab the link here
1076.48 -> we're going to clone the repo
1083.039 -> you're going to open up a vs code window
1089.84 -> all right so if we look in the
1092.88 -> source directory this code was written
1095.919 -> in java
1098.16 -> we have three handlers for
1101.919 -> three confirmation actions create delete
1104.799 -> and read
1106 -> we're going to look at the create
1107.2 -> handler code
1109.6 -> this handler has an entry point here at
1111.919 -> line 49
1112.88 -> it's the create handler class and uh one
1116.4 -> of the first things that that we do when
1118.4 -> this
1118.799 -> handler is invoked is we check for
1120.88 -> callback context
1122.799 -> if the callback context is null we know
1125.2 -> that this is the
1126.24 -> first invocation of the create handler
1129.2 -> and
1130.08 -> what we do is some checks and
1132 -> validations
1133.12 -> um to ensure that the
1136.24 -> the caller has the right permissions um
1140.08 -> that other things are are in the right
1143.6 -> state
1144.799 -> before we provision that ec2 instance
1147.36 -> provisioning the
1148.32 -> instance is a relatively expensive call
1150.24 -> so we want to make sure that
1152.48 -> everything is in place before we
1155.52 -> spin that ec2 instance up so if we look
1158.16 -> at one
1158.799 -> of the first checks that we do we check
1161.84 -> to see if
1164 -> the caller has the terminate instances
1166.4 -> permission
1168 -> so we checked that by running a policy
1170.32 -> simulation
1171.28 -> and if that simulation fails we're going
1174.48 -> to return
1175.2 -> a progress event with the status of
1177.76 -> failed
1179.12 -> along with an error code of invalid
1180.96 -> request and a descriptive message
1183.039 -> letting the user know what happened
1185.12 -> and how to fix the issue
1189.28 -> we run a number of other checks and
1191.6 -> validations
1192.559 -> but we're just going to assume that
1194.16 -> everything
1195.6 -> passes if it does
1198.96 -> we end up here on line 258
1202.48 -> where we invoke the create the cloud
1205.919 -> formation create stack
1207.84 -> api so and in this code we're using uh
1211.36 -> cloud formation to manage the
1213.6 -> uh life cycle and to provision that ec2
1218.84 -> resource
1221.039 -> immediately after creating uh
1224.32 -> the stack to provision the ins the ec2
1226.559 -> instance we're going to return
1227.679 -> a progress event with a status of
1230.96 -> in progress we're going to set a
1233.12 -> callback delay
1234.24 -> of 90 seconds and we're also going to
1237.28 -> set a
1238.159 -> callback context that contains the stack
1241.28 -> name
1242.08 -> and the stack id
1245.28 -> so after 90 seconds cloudformation is
1248.88 -> going to
1249.52 -> reinvoke this create handler so we're
1252.4 -> going to end up back here
1254.32 -> at the entry point
1258.159 -> this time though the callback contact is
1260.96 -> not going to be null
1262.32 -> it's going to have the stack name and
1265.6 -> stack id that that we
1267.28 -> set earlier so what's going to happen is
1270.64 -> we're going to end up in this else block
1272.799 -> on this invocation one of the first
1275.6 -> things we do here is we
1277.039 -> uh get that stack name from the callback
1279.679 -> context
1282 -> and we're going to do a confirmation
1285.28 -> describe stacks api call
1288.559 -> to get the provisioning status of that
1292.72 -> ec2 instance we want to know if that
1295.44 -> ec2 instance has been successfully
1298.72 -> provisioned and that the bash command
1300.64 -> has completed its work and that we've
1302.64 -> got we received the output
1306 -> and that would be the case if we reached
1307.84 -> a a terminal state
1311.039 -> so if we've reached a terminal state
1313.12 -> that means that either things have gone
1315.039 -> really well and we have a terminal state
1318.159 -> of create complete
1319.52 -> um it also can mean that we um that
1322.48 -> something went wrong
1323.52 -> um and in that case we would um
1327.44 -> see that the stack has a status of
1329.84 -> create failed or
1330.96 -> potentially roll back so if we've
1333.6 -> reached a
1334.32 -> terminal state we determine which state
1337.6 -> we've ended up in if it's
1341.36 -> reached a state of create complete that
1343.679 -> means that the ec2 instance successfully
1345.919 -> provisioned the bash command
1347.36 -> ran and everything uh worked out
1350.48 -> as we intended and we reached the end of
1354.159 -> the happy path
1355.679 -> and in that case we're going to return a
1358 -> progress event
1359.44 -> of success which means that cloud
1362.72 -> formation is going to
1364 -> mark the resource as successfully
1366.559 -> provisioned
1367.44 -> and it's going to continue provisioning
1369.84 -> any other resource you have
1371.44 -> in that stack if however
1375.52 -> that we reached a terminal state where
1378.4 -> that
1379.039 -> something went wrong where you know the
1381.36 -> the stack did not provision the ec2
1383.52 -> instance
1384.72 -> there's an error that means that we've
1386.96 -> reached a terminal state
1388.08 -> where the stack status is either create
1391.039 -> failed or
1391.84 -> uh it might be rolled back and in that
1395.12 -> case we're going to return a
1397.12 -> progress event uh uh with a status of
1400.84 -> failed
1402 -> we're going to set an error code if not
1403.44 -> stabilized as well as provide
1405.919 -> a descriptive message to the user
1408 -> letting them know what happened
1409.76 -> and what next steps they should take to
1412.799 -> debug
1414.08 -> here we provide the stack name so that
1416.08 -> they can go
1417.28 -> um and um investigate what happened to
1420.72 -> that ec2 instance
1423.36 -> okay um however you know uh it's
1426.88 -> possible that the ec2 instance
1429.2 -> is has not reached that terminal state
1431.84 -> that
1432.32 -> the the instance is um still running
1435.919 -> maybe there's some complex bash code
1438.4 -> that needs
1439.679 -> a a little bit more time
1443.36 -> and in that case uh we're going to end
1445.36 -> up uh we're going to end up here
1447.84 -> um in this case it means that
1451.279 -> that that we still need a little bit
1453.12 -> more time to let that ec2 instance
1455.52 -> finish its work
1456.64 -> so here we're going to return a progress
1459.039 -> event
1460 -> with a status of in progress we're going
1462.32 -> to set a callback delay
1464.08 -> of 30 seconds this time we're also going
1467.279 -> to set that callback context again
1469.84 -> with the stack name and the
1472.96 -> stack id at this point
1476.24 -> uh cloudformation waits uh 30 seconds
1479.6 -> and then it's going to reinvoke the
1481.279 -> create handler again
1483.12 -> so we can continue returning in progress
1485.2 -> we're up to um
1487.52 -> two hours by default up to a maximum of
1490.4 -> 36 hours
1491.919 -> the length of that timeout is set in the
1495.36 -> schema file
1497.36 -> the name of the property that defines
1500.48 -> that timeout is called timeout in
1502.159 -> minutes
1503.84 -> and that's the quick demo of the command
1507.279 -> render resource type
1509.039 -> it's an example of a resource type
1512.159 -> that uses callbacks if you'd like to
1514.559 -> inspect the code it's in github
1516.64 -> i'll just use the qr code at the
1519.039 -> beginning of this demo to
1520.64 -> navigate to the blog and the github
1523.76 -> uh the link is is in that blog
1527.44 -> so if you'd like to see enhancements to
1529.76 -> this resource type or if you have any
1531.44 -> issues with
1532.799 -> uh using it or provisioning it uh we
1535.6 -> encourage you to submit
1536.799 -> an issue in the repo or um
1540.08 -> or a pull request so that's it so thanks
1543.44 -> again
1543.919 -> for your time please remember to fill
1546.559 -> out your
1547.919 -> session survey

Source: https://www.youtube.com/watch?v=qjtsuTVgrjs