pipedream 0.1.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.cody/buildspec.yml +9 -0
  3. data/.cody/project.rb +4 -0
  4. data/.gitignore +16 -11
  5. data/.gitmodules +9 -0
  6. data/.rspec +1 -1
  7. data/CHANGELOG.md +34 -0
  8. data/Gemfile +3 -1
  9. data/Gemfile.lock +112 -0
  10. data/Guardfile +19 -0
  11. data/LICENSE.txt +18 -17
  12. data/README.md +55 -21
  13. data/Rakefile +10 -2
  14. data/exe/pipe +14 -0
  15. data/exe/pipedream +14 -0
  16. data/lib/pipedream/autoloader.rb +21 -0
  17. data/lib/pipedream/aws_services/helpers.rb +71 -0
  18. data/lib/pipedream/aws_services.rb +20 -0
  19. data/lib/pipedream/build.rb +13 -0
  20. data/lib/pipedream/cli.rb +60 -0
  21. data/lib/pipedream/command.rb +82 -0
  22. data/lib/pipedream/completer/script.rb +6 -0
  23. data/lib/pipedream/completer/script.sh +10 -0
  24. data/lib/pipedream/completer.rb +159 -0
  25. data/lib/pipedream/core.rb +63 -0
  26. data/lib/pipedream/create.rb +12 -0
  27. data/lib/pipedream/delete.rb +27 -0
  28. data/lib/pipedream/deploy.rb +40 -0
  29. data/lib/pipedream/dsl/pipeline/approve.rb +34 -0
  30. data/lib/pipedream/dsl/pipeline/codebuild.rb +57 -0
  31. data/lib/pipedream/dsl/pipeline/github.rb +42 -0
  32. data/lib/pipedream/dsl/pipeline.rb +37 -0
  33. data/lib/pipedream/dsl/role.rb +50 -0
  34. data/lib/pipedream/dsl/schedule.rb +30 -0
  35. data/lib/pipedream/dsl/sns.rb +15 -0
  36. data/lib/pipedream/dsl/ssm.rb +22 -0
  37. data/lib/pipedream/dsl/webhook.rb +27 -0
  38. data/lib/pipedream/evaluate.rb +47 -0
  39. data/lib/pipedream/help/completion.md +22 -0
  40. data/lib/pipedream/help/completion_script.md +3 -0
  41. data/lib/pipedream/help/deploy.md +54 -0
  42. data/lib/pipedream/help/start.md +20 -0
  43. data/lib/pipedream/help.rb +9 -0
  44. data/lib/pipedream/init.rb +68 -0
  45. data/lib/pipedream/pipeline/s3_bucket.rb +88 -0
  46. data/lib/pipedream/pipeline.rb +61 -0
  47. data/lib/pipedream/role.rb +181 -0
  48. data/lib/pipedream/schedule.rb +99 -0
  49. data/lib/pipedream/sequence.rb +66 -0
  50. data/lib/pipedream/setting.rb +82 -0
  51. data/lib/pipedream/sns.rb +43 -0
  52. data/lib/pipedream/stack.rb +95 -0
  53. data/lib/pipedream/start.rb +84 -0
  54. data/lib/pipedream/update.rb +12 -0
  55. data/lib/pipedream/version.rb +1 -1
  56. data/lib/pipedream/webhook.rb +60 -0
  57. data/lib/pipedream.rb +18 -1
  58. data/lib/template/.pipedream/pipeline.rb.tt +40 -0
  59. data/lib/template/.pipedream/schedule.rb +3 -0
  60. data/lib/template/.pipedream/settings.yml +9 -0
  61. data/lib/template/.pipedream/sns.rb +14 -0
  62. data/pipedream.gemspec +25 -14
  63. data/vendor/aws_data/CHANGELOG.md +7 -0
  64. data/vendor/aws_data/Gemfile +4 -0
  65. data/vendor/aws_data/Gemfile.lock +48 -0
  66. data/vendor/aws_data/LICENSE.txt +21 -0
  67. data/vendor/aws_data/README.md +42 -0
  68. data/vendor/aws_data/Rakefile +6 -0
  69. data/vendor/aws_data/aws_data.gemspec +30 -0
  70. data/{bin → vendor/aws_data/bin}/console +1 -1
  71. data/{bin → vendor/aws_data/bin}/setup +0 -0
  72. data/vendor/aws_data/lib/aws_data/version.rb +3 -0
  73. data/vendor/aws_data/lib/aws_data.rb +91 -0
  74. data/vendor/aws_data/spec/aws_data_spec.rb +5 -0
  75. data/vendor/aws_data/spec/spec_helper.rb +14 -0
  76. data/vendor/cfn-status/Gemfile +4 -0
  77. data/vendor/cfn-status/Gemfile.lock +49 -0
  78. data/vendor/cfn-status/LICENSE.txt +21 -0
  79. data/vendor/cfn-status/README.md +56 -0
  80. data/vendor/cfn-status/Rakefile +6 -0
  81. data/vendor/cfn-status/bin/console +14 -0
  82. data/vendor/cfn-status/bin/setup +8 -0
  83. data/vendor/cfn-status/cfn-status.gemspec +30 -0
  84. data/vendor/cfn-status/lib/cfn/aws_service.rb +56 -0
  85. data/vendor/cfn-status/lib/cfn/status/version.rb +5 -0
  86. data/vendor/cfn-status/lib/cfn/status.rb +220 -0
  87. data/vendor/cfn-status/spec/cfn/status_spec.rb +81 -0
  88. data/vendor/cfn-status/spec/fixtures/cfn/stack-events-complete.json +1080 -0
  89. data/vendor/cfn-status/spec/fixtures/cfn/stack-events-in-progress.json +1080 -0
  90. data/vendor/cfn-status/spec/fixtures/cfn/stack-events-update-rollback-complete.json +1086 -0
  91. data/vendor/cfn-status/spec/spec_helper.rb +14 -0
  92. data/vendor/cfn_camelizer/CHANGELOG.md +10 -0
  93. data/vendor/cfn_camelizer/Gemfile +4 -0
  94. data/vendor/cfn_camelizer/LICENSE.txt +21 -0
  95. data/vendor/cfn_camelizer/README.md +40 -0
  96. data/vendor/cfn_camelizer/Rakefile +6 -0
  97. data/vendor/cfn_camelizer/bin/console +14 -0
  98. data/vendor/cfn_camelizer/bin/setup +8 -0
  99. data/vendor/cfn_camelizer/cfn_camelizer.gemspec +32 -0
  100. data/vendor/cfn_camelizer/lib/camelizer.yml +27 -0
  101. data/vendor/cfn_camelizer/lib/cfn_camelizer/version.rb +3 -0
  102. data/vendor/cfn_camelizer/lib/cfn_camelizer.rb +92 -0
  103. data/vendor/cfn_camelizer/spec/cfn_camelizer_spec.rb +79 -0
  104. data/vendor/cfn_camelizer/spec/spec_helper.rb +14 -0
  105. metadata +295 -23
  106. data/.travis.yml +0 -7
@@ -0,0 +1,27 @@
1
+ module Pipedream::Dsl
2
+ module Webhook
3
+ include Ssm
4
+
5
+ # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codepipeline-webhook.html
6
+ PROPERTIES = %w[
7
+ authentication
8
+ authentication_configuration
9
+ filters
10
+ name
11
+ register_with_third_party
12
+ target_action
13
+ target_pipeline
14
+ target_pipeline_version
15
+ ]
16
+ PROPERTIES.each do |prop|
17
+ define_method(prop) do |v|
18
+ @properties[prop.to_sym] = v
19
+ end
20
+ end
21
+
22
+ def secret_token(v)
23
+ @secret_token = v
24
+ end
25
+ alias_method :github_token, :secret_token
26
+ end
27
+ end
@@ -0,0 +1,47 @@
1
+ module Pipedream
2
+ module Evaluate
3
+ def evaluate(path)
4
+ source_code = IO.read(path)
5
+ begin
6
+ instance_eval(source_code, path)
7
+ rescue Exception => e
8
+ if e.class == SystemExit # allow exit to happen normally
9
+ raise
10
+ else
11
+ task_definition_error(e)
12
+ puts "\nFull error:"
13
+ raise
14
+ end
15
+ end
16
+ end
17
+
18
+ private
19
+ # Prints out a user friendly task_definition error message
20
+ def task_definition_error(e)
21
+ error_info = e.backtrace.first
22
+ path, line_no, _ = error_info.split(':')
23
+ line_no = line_no.to_i
24
+ puts "Error evaluating #{path}:".color(:red)
25
+ puts e.message
26
+ puts "Here's the line in #{path} with the error:\n\n"
27
+
28
+ contents = IO.read(path)
29
+ content_lines = contents.split("\n")
30
+ context = 5 # lines of context
31
+ top, bottom = [line_no-context-1, 0].max, line_no+context-1
32
+ spacing = content_lines.size.to_s.size
33
+ content_lines[top..bottom].each_with_index do |line_content, index|
34
+ line_number = top+index+1
35
+ if line_number == line_no
36
+ printf("%#{spacing}d %s\n".color(:red), line_number, line_content)
37
+ else
38
+ printf("%#{spacing}d %s\n", line_number, line_content)
39
+ end
40
+ end
41
+ end
42
+
43
+ def lookup_codepipeline_file(name)
44
+ [".pipedream", @options[:type], name].compact.join("/")
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,22 @@
1
+ Example:
2
+
3
+ pipe completion
4
+
5
+ Prints words for TAB auto-completion.
6
+
7
+ Examples:
8
+
9
+ pipe completion
10
+ pipe completion hello
11
+ pipe completion hello name
12
+
13
+ To enable, TAB auto-completion add the following to your profile:
14
+
15
+ eval $(pipe completion_script)
16
+
17
+ Auto-completion example usage:
18
+
19
+ pipe [TAB]
20
+ pipe hello [TAB]
21
+ pipe hello name [TAB]
22
+ pipe hello name --[TAB]
@@ -0,0 +1,3 @@
1
+ To use, add the following to your `~/.bashrc` or `~/.profile`
2
+
3
+ eval $(pipe completion_script)
@@ -0,0 +1,54 @@
1
+ Examples:
2
+
3
+ pipe deploy
4
+ pipe deploy demo # explicitly specify pipeline name
5
+ pipe deploy demo -b mybranch # specify git branch
6
+
7
+ The pipeline is generated from the DSL and created with CloudFormation. The files that the DSL evaluates are in the `.pipedream` folder:
8
+
9
+ .pipedream/pipeline.rb
10
+ .pipedream/role.rb
11
+ .pipedream/schedule.rb
12
+ .pipedream/webhook.rb
13
+
14
+ To create the CodePipeline pipeline, you run:
15
+
16
+ pipe deploy
17
+
18
+ You'll see output that looks something like this:
19
+
20
+ $ pipe deploy
21
+ Generated CloudFormation template at /tmp/codepipeline.yml
22
+ Deploying stack demo-pipe with CodePipeline project demo
23
+ Creating stack demo-pipe. Check CloudFormation console for status.
24
+ Stack name demo-pipe status CREATE_IN_PROGRESS
25
+ Here's the CloudFormation url to check for more details https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks
26
+ Waiting for stack to complete
27
+ 04:14:03AM CREATE_IN_PROGRESS AWS::CloudFormation::Stack demo-pipe User Initiated
28
+ 04:14:06AM CREATE_IN_PROGRESS AWS::IAM::Role IamRole
29
+ 04:14:07AM CREATE_IN_PROGRESS AWS::IAM::Role IamRole Resource creation Initiated
30
+ 04:14:25AM CREATE_COMPLETE AWS::IAM::Role IamRole
31
+ 04:14:28AM CREATE_IN_PROGRESS AWS::CodePipeline::Pipeline Pipeline
32
+ 04:14:29AM CREATE_IN_PROGRESS AWS::CodePipeline::Pipeline Pipeline Resource creation Initiated
33
+ 04:14:29AM CREATE_COMPLETE AWS::CodePipeline::Pipeline Pipeline
34
+ 04:14:31AM CREATE_IN_PROGRESS AWS::CodePipeline::Webhook Webhook
35
+ 04:14:33AM CREATE_IN_PROGRESS AWS::CodePipeline::Webhook Webhook Resource creation Initiated
36
+ 04:14:33AM CREATE_COMPLETE AWS::CodePipeline::Webhook Webhook
37
+ 04:14:35AM CREATE_COMPLETE AWS::CloudFormation::Stack demo-pipe
38
+ Stack success status: CREATE_COMPLETE
39
+ Time took for stack deployment: 35s.
40
+ $
41
+
42
+ ## Explicit Pipeline Name
43
+
44
+ By default, the pipeline name is inferred and is the parent folder that you are within. You can explicitly specify the pipeline name as the first CLI argument:
45
+
46
+ pipe deploy my-pipeline
47
+
48
+ ## Specify Git Branch
49
+
50
+ It is useful to build pipelines with different source git branches. You can pass a `--branch` option to the `pipe deploy` command. The cli `—-branch` option always takes the highest precedence. Example:
51
+
52
+ pipe deploy my-pipeline --branch my-branch
53
+
54
+ Note: When you specify a branch pipedream actually first updates the pipeline before starting the pipeline execution. This is done because CodePipeline does not natively support specifying the branch. It is discussed more here: [Using Different Branches]({% link _docs/examples/different-branches.md %}).
@@ -0,0 +1,20 @@
1
+ You can start a pipeline with the `pipe start` command. Here's an example:
2
+
3
+ $ pipe start
4
+ Pipeline started: demo
5
+ Please check the CodePipeline console for the status.
6
+ CodePipeline Console: https://us-west-2.console.aws.amazon.com/codesuite/codepipeline/pipelines/demo/view
7
+ Pipeline cli: aws codepipeline get-pipeline-execution --pipeline-execution-id 02579d64-9271-4edc-aa45-bc9629d732bb --pipeline-name demo
8
+ $
9
+
10
+ ## Specifying Code Branch
11
+
12
+ If you would like start a build using a specific code branch you can use the `--branch` or `-b` option. Example:
13
+
14
+ pipe start -b feature-branch
15
+
16
+ ## AWS CLI Equivalent
17
+
18
+ The `pipe start` command is a simple wrapper to the AWS API with the ruby sdk. You can also start pipelines with the `aws codepipeline` cli. Here's the equivalent CLI command:
19
+
20
+ aws codepipeline start-pipeline-execution --name demo
@@ -0,0 +1,9 @@
1
+ module Pipedream::Help
2
+ class << self
3
+ def text(namespaced_command)
4
+ path = namespaced_command.to_s.gsub(':','/')
5
+ path = File.expand_path("../help/#{path}.md", __FILE__)
6
+ IO.read(path) if File.exist?(path)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,68 @@
1
+ module Pipedream
2
+ class Init < Sequence
3
+ # Ugly, this is how I can get the options from to match with this Thor::Group
4
+ def self.cli_options
5
+ [
6
+ [:name, desc: "CodePipeline project name."],
7
+ [:mode, desc: "Modes: light or full", default: "light" ],
8
+ [:force, type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files."],
9
+ [:template, desc: "Custom template to use."],
10
+ [:template_mode, desc: "Template mode: replace or additive."],
11
+ ]
12
+ end
13
+ cli_options.each { |o| class_option(*o) }
14
+
15
+ def setup_template_repo
16
+ return unless @options[:template]&.include?('/')
17
+
18
+ sync_template_repo
19
+ end
20
+
21
+ def set_source_path
22
+ return unless @options[:template]
23
+
24
+ custom_template = "#{ENV['HOME']}/.pipedream/templates/#{full_repo_name}"
25
+
26
+ if @options[:template_mode] == "replace" # replace the template entirely
27
+ override_source_paths(custom_template)
28
+ else # additive: modify on top of default template
29
+ default_template = File.expand_path("../../template", __FILE__)
30
+ override_source_paths([custom_template, default_template])
31
+ end
32
+ end
33
+
34
+ def copy_project
35
+ puts "Initialize codepipeline project in .pipedream"
36
+
37
+ excludes = %w[.git]
38
+ if @options[:mode] == "light"
39
+ excludes += %w[
40
+ settings.yml
41
+ sns.rb
42
+ ]
43
+ end
44
+ pattern = Regexp.new(excludes.join('|'))
45
+
46
+ if @options[:template]
47
+ directory ".", ".pipedream", exclude_pattern: pattern
48
+ else
49
+ directory ".", exclude_pattern: pattern
50
+ end
51
+ end
52
+
53
+ private
54
+ def project_name
55
+ inferred_name = File.basename(Dir.pwd).gsub('_','-').gsub(/[^0-9a-zA-Z,-]/, '')
56
+ @options[:name] || inferred_name
57
+ end
58
+
59
+ def project_github_repo
60
+ default = "user/repo"
61
+ return default unless File.exist?(".git/config") && git_installed?
62
+
63
+ url = `git config --get remote.origin.url`.strip
64
+ repo = Dsl::Pipeline::Github.extract_repo_source(url)
65
+ repo == '' ? default : repo
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,88 @@
1
+ require "aws-sdk-s3"
2
+
3
+ class Pipedream::Pipeline
4
+ class S3Bucket
5
+ extend Memoist
6
+ include Pipedream::AwsServices
7
+
8
+ class << self
9
+ extend Memoist
10
+ def name
11
+ new.name
12
+ end
13
+ memoize :name
14
+ end
15
+
16
+ def name
17
+ ensure_exists(bucket_name)
18
+ bucket_name
19
+ end
20
+ memoize :name
21
+
22
+ def bucket_name
23
+ "codepipeline-#{aws.region}-#{aws.account}"
24
+ end
25
+
26
+ def ensure_exists(name)
27
+ return if exists?(name) || ENV['TEST']
28
+ s3.create_bucket(bucket: name)
29
+ policy = {
30
+ "Version": "2012-10-17",
31
+ "Id": "SSEAndSSLPolicy",
32
+ "Statement": [
33
+ {
34
+ "Sid": "DenyUnEncryptedObjectUploads",
35
+ "Effect": "Deny",
36
+ "Principal": "*",
37
+ "Action": "s3:PutObject",
38
+ "Resource": "arn:aws:s3:::#{name}/*",
39
+ "Condition": {
40
+ "StringNotEquals": {
41
+ "s3:x-amz-server-side-encryption": "aws:kms"
42
+ }
43
+ }
44
+ },
45
+ {
46
+ "Sid": "DenyInsecureConnections",
47
+ "Effect": "Deny",
48
+ "Principal": "*",
49
+ "Action": "s3:*",
50
+ "Resource": "arn:aws:s3:::#{name}/*",
51
+ "Condition": {
52
+ "Bool": {
53
+ "aws:SecureTransport": "false"
54
+ }
55
+ }
56
+ }
57
+ ]
58
+ }
59
+ s3.put_bucket_policy(
60
+ bucket: name,
61
+ policy: JSON.dump(policy),
62
+ )
63
+ rescue Aws::S3::Errors::BucketAlreadyExists => e
64
+ puts "ERROR #{e.class}: #{e.message}".color(:red)
65
+ puts "Bucket name: #{name}"
66
+ exit 1
67
+ end
68
+
69
+ def exists?(name)
70
+ begin
71
+ s3.head_bucket(bucket: name)
72
+ true
73
+ rescue Aws::S3::Errors::BucketAlreadyOwnedByYou, Aws::S3::Errors::Http301Error
74
+ # These exceptions indicate bucket already exists
75
+ # Aws::S3::Errors::Http301Error could be inaccurate but compromising for simplicity
76
+ true
77
+ rescue
78
+ false
79
+ end
80
+ end
81
+
82
+ private
83
+ def aws
84
+ AwsData.new
85
+ end
86
+ memoize :aws
87
+ end
88
+ end
@@ -0,0 +1,61 @@
1
+ module Pipedream
2
+ class Pipeline
3
+ extend Memoist
4
+ include Dsl::Pipeline
5
+ include Evaluate
6
+
7
+ def initialize(options={})
8
+ @options = options
9
+ @pipeline_path = options[:pipeline_path] || get_pipeline_path
10
+ @properties = default_properties # defaults make pipeline.rb simpler
11
+ @stages = []
12
+ end
13
+
14
+ def run
15
+ evaluate(@pipeline_path)
16
+ @properties[:stages] ||= @stages
17
+ set_source_branch!
18
+
19
+ resource = {
20
+ pipeline: {
21
+ type: "AWS::CodePipeline::Pipeline",
22
+ properties: @properties
23
+ }
24
+ }
25
+ CfnCamelizer.transform(resource)
26
+ end
27
+
28
+ def default_properties
29
+ {
30
+ name: @options[:full_pipeline_name],
31
+ role_arn: { "Fn::GetAtt": "IamRole.Arn" },
32
+ artifact_store: {
33
+ type: "S3",
34
+ location: s3_bucket, # auto creates s3 bucket
35
+ }
36
+ }
37
+ end
38
+
39
+ # cli branch option always takes highest precedence
40
+ def set_source_branch!
41
+ return unless @options[:branch]
42
+
43
+ source_stage = @properties[:stages].first
44
+ action = source_stage[:actions].first
45
+ action[:configuration][:branch] = @options[:branch]
46
+ end
47
+
48
+ def exist?
49
+ File.exist?(@pipeline_path)
50
+ end
51
+
52
+ def s3_bucket
53
+ S3Bucket.name
54
+ end
55
+
56
+ private
57
+ def get_pipeline_path
58
+ lookup_codepipeline_file "pipeline.rb"
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,181 @@
1
+ require "yaml"
2
+
3
+ module Pipedream
4
+ class Role
5
+ include Pipedream::Dsl::Role
6
+ include Evaluate
7
+
8
+ def initialize(options={})
9
+ @options = options
10
+ @role_path = options[:role_path] || get_role_path
11
+ @properties = default_properties
12
+ end
13
+
14
+ def run
15
+ evaluate(@role_path) if File.exist?(@role_path)
16
+ @properties[:policies] = [{
17
+ policy_name: "CodePipelineAccess",
18
+ policy_document: {
19
+ version: "2012-10-17",
20
+ statement: derived_iam_statements
21
+ }
22
+ }]
23
+
24
+ @properties[:managed_policy_arns] = @managed_policy_arns if @managed_policy_arns && !@managed_policy_arns.empty?
25
+
26
+ resource = {
27
+ logical_id => {
28
+ type: "AWS::IAM::Role",
29
+ properties: @properties
30
+ }
31
+ }
32
+ CfnCamelizer.transform(resource)
33
+ end
34
+
35
+ def logical_id
36
+ "IamRole"
37
+ end
38
+
39
+ private
40
+ def get_role_path
41
+ lookup_codepipeline_file("role.rb")
42
+ end
43
+
44
+ def default_properties
45
+ {
46
+ assume_role_policy_document: {
47
+ statement: [{
48
+ action: ["sts:AssumeRole"],
49
+ effect: "Allow",
50
+ principal: {
51
+ service: principal_services
52
+ }
53
+ }],
54
+ version: "2012-10-17"
55
+ },
56
+ path: "/"
57
+ }
58
+ end
59
+
60
+ def principal_services
61
+ ["codepipeline.amazonaws.com"]
62
+ end
63
+
64
+ def derived_iam_statements
65
+ @iam_statements || default_iam_statements
66
+ end
67
+
68
+ def default_iam_statements
69
+ # Based on the one created by CodePipeline Console
70
+ [{
71
+ "action"=>["iam:PassRole"],
72
+ "resource"=>"*",
73
+ "effect"=>"Allow",
74
+ "condition"=>
75
+ {"string_equals_if_exists"=>
76
+ {"iam:passed_to_service"=>
77
+ ["cloudformation.amazonaws.com",
78
+ "elasticbeanstalk.amazonaws.com",
79
+ "ec2.amazonaws.com",
80
+ "ecs-tasks.amazonaws.com"]
81
+ }
82
+ }
83
+ },{
84
+ "action"=>
85
+ ["codecommit:CancelUploadArchive",
86
+ "codecommit:GetBranch",
87
+ "codecommit:GetCommit",
88
+ "codecommit:GetUploadArchiveStatus",
89
+ "codecommit:UploadArchive"],
90
+ "resource"=>"*",
91
+ "effect"=>"Allow"
92
+ },{
93
+ "action"=>
94
+ ["codedeploy:CreateDeployment",
95
+ "codedeploy:GetApplication",
96
+ "codedeploy:GetApplicationRevision",
97
+ "codedeploy:GetDeployment",
98
+ "codedeploy:GetDeploymentConfig",
99
+ "codedeploy:RegisterApplicationRevision"],
100
+ "resource"=>"*",
101
+ "effect"=>"Allow"
102
+ },{
103
+ "action"=>
104
+ ["elasticbeanstalk:*",
105
+ "ec2:*",
106
+ "elasticloadbalancing:*",
107
+ "autoscaling:*",
108
+ "cloudwatch:*",
109
+ "s3:*",
110
+ "sns:*",
111
+ "cloudformation:*",
112
+ "rds:*",
113
+ "sqs:*",
114
+ "ecs:*"],
115
+ "resource"=>"*",
116
+ "effect"=>"Allow"
117
+ },{
118
+ "action"=>["lambda:InvokeFunction", "lambda:ListFunctions"],
119
+ "resource"=>"*",
120
+ "effect"=>"Allow"
121
+ },{
122
+ "action"=>
123
+ ["opsworks:CreateDeployment",
124
+ "opsworks:DescribeApps",
125
+ "opsworks:DescribeCommands",
126
+ "opsworks:DescribeDeployments",
127
+ "opsworks:DescribeInstances",
128
+ "opsworks:DescribeStacks",
129
+ "opsworks:UpdateApp",
130
+ "opsworks:UpdateStack"],
131
+ "resource"=>"*",
132
+ "effect"=>"Allow"
133
+ },{
134
+ "action"=>
135
+ ["cloudformation:CreateStack",
136
+ "cloudformation:DeleteStack",
137
+ "cloudformation:DescribeStacks",
138
+ "cloudformation:UpdateStack",
139
+ "cloudformation:CreateChangeSet",
140
+ "cloudformation:DeleteChangeSet",
141
+ "cloudformation:DescribeChangeSet",
142
+ "cloudformation:ExecuteChangeSet",
143
+ "cloudformation:SetStackPolicy",
144
+ "cloudformation:ValidateTemplate"],
145
+ "resource"=>"*",
146
+ "effect"=>"Allow"
147
+ },{
148
+ "action"=>["codebuild:BatchGetBuilds", "codebuild:StartBuild"],
149
+ "resource"=>"*",
150
+ "effect"=>"Allow"
151
+ },{
152
+ "action"=>
153
+ ["devicefarm:ListProjects",
154
+ "devicefarm:ListDevicePools",
155
+ "devicefarm:GetRun",
156
+ "devicefarm:GetUpload",
157
+ "devicefarm:CreateUpload",
158
+ "devicefarm:ScheduleRun"],
159
+ "resource"=>"*",
160
+ "effect"=>"Allow",
161
+ },{
162
+ "action"=>
163
+ ["servicecatalog:ListProvisioningArtifacts",
164
+ "servicecatalog:CreateProvisioningArtifact",
165
+ "servicecatalog:DescribeProvisioningArtifact",
166
+ "servicecatalog:DeleteProvisioningArtifact",
167
+ "servicecatalog:UpdateProduct"],
168
+ "resource"=>"*",
169
+ "effect"=>"Allow",
170
+ },{
171
+ "action"=>["cloudformation:ValidateTemplate"],
172
+ "resource"=>"*",
173
+ "effect"=>"Allow",
174
+ },{
175
+ "action"=>["ecr:DescribeImages"],
176
+ "resource"=>"*",
177
+ "effect"=>"Allow",
178
+ }]
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,99 @@
1
+ module Pipedream
2
+ class Schedule
3
+ include Pipedream::Dsl::Schedule
4
+ include Evaluate
5
+
6
+ def initialize(options={})
7
+ @options = options
8
+ @schedule_path = options[:schedule_path] || get_schedule_path
9
+ @properties = default_properties
10
+ end
11
+
12
+ def run
13
+ return unless File.exist?(@schedule_path)
14
+
15
+ old_properties = @properties.clone
16
+ evaluate(@schedule_path)
17
+
18
+ @properties[:schedule_expression] = @schedule_expression if @schedule_expression
19
+ set_rule_event! if @rule_event_props
20
+ return if old_properties == @properties # empty schedule.rb file
21
+
22
+ resource = {
23
+ events_rule: {
24
+ type: "AWS::Events::Rule",
25
+ properties: @properties
26
+ },
27
+ events_rule_role: events_rule_role,
28
+ }
29
+ CfnCamelizer.transform(resource)
30
+ end
31
+
32
+ def set_rule_event!
33
+ props = @rule_event_props
34
+ if props.key?(:detail)
35
+ description = props.key?(:description) ? props.delete(:description) : rule_description
36
+ rule_props = { event_pattern: props, description: description }
37
+ else # if props.key?(:event_pattern)
38
+ props[:description] ||= rule_description
39
+ rule_props = props
40
+ end
41
+
42
+ @properties.merge!(rule_props)
43
+ end
44
+
45
+ def default_properties
46
+ description = "CodePipeline #{@options[:full_pipeline_name]}"
47
+ name = description.gsub(" ", "-").downcase
48
+ {
49
+ description: description,
50
+ # event_pattern: ,
51
+ name: name,
52
+ # schedule_expression: ,
53
+ state: "ENABLED",
54
+ targets: [{
55
+ arn: "arn:aws:codepipeline:#{aws.region}:#{aws.account}:#{@options[:full_pipeline_name]}",
56
+ role_arn: { "Fn::GetAtt": "EventsRuleRole.Arn" }, # required for specific CodePipeline target.
57
+ id: "CodePipelineTarget",
58
+ }]
59
+ }
60
+ end
61
+
62
+ private
63
+ def get_schedule_path
64
+ lookup_codepipeline_file("schedule.rb")
65
+ end
66
+
67
+ def events_rule_role
68
+ {
69
+ type: "AWS::IAM::Role",
70
+ properties: {
71
+ assume_role_policy_document: {
72
+ statement: [{
73
+ action: [ "sts:AssumeRole" ],
74
+ effect: "Allow",
75
+ principal: { service: [ "events.amazonaws.com" ] }
76
+ }],
77
+ version: "2012-10-17"
78
+ },
79
+ path: "/",
80
+ policies: [{
81
+ policy_name: "CodePipelineAccess",
82
+ policy_document: {
83
+ version: "2012-10-17",
84
+ statement: [{
85
+ action: "codepipeline:StartPipelineExecution",
86
+ effect: "Allow",
87
+ resource: "arn:aws:codepipeline:#{aws.region}:#{aws.account}:#{@options[:full_pipeline_name]}"
88
+ }]
89
+ }
90
+ }]
91
+ }
92
+ }
93
+ end
94
+
95
+ def aws
96
+ @aws ||= AwsData.new
97
+ end
98
+ end
99
+ end