aws-codedeploy-agent 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/.gitignore +2 -0
  2. data/CHANGES.md +3 -0
  3. data/Gemfile +13 -0
  4. data/LICENSE +177 -0
  5. data/NOTICE +2 -0
  6. data/README.md +16 -0
  7. data/aws-codedeploy-agent.gemspec +39 -0
  8. data/bin/codedeploy-agent +78 -0
  9. data/bin/codedeploy-install +15 -0
  10. data/bin/codedeploy-uninstall +13 -0
  11. data/certs/host-agent-deployment-signer-ca-chain.pem +76 -0
  12. data/conf/codedeployagent.yml +9 -0
  13. data/init.d/codedeploy-agent +61 -0
  14. data/lib/core_ext.rb +71 -0
  15. data/lib/instance_agent.rb +35 -0
  16. data/lib/instance_agent/agent/base.rb +34 -0
  17. data/lib/instance_agent/codedeploy_plugin/application_specification/ace_info.rb +133 -0
  18. data/lib/instance_agent/codedeploy_plugin/application_specification/acl_info.rb +163 -0
  19. data/lib/instance_agent/codedeploy_plugin/application_specification/application_specification.rb +142 -0
  20. data/lib/instance_agent/codedeploy_plugin/application_specification/context_info.rb +23 -0
  21. data/lib/instance_agent/codedeploy_plugin/application_specification/file_info.rb +23 -0
  22. data/lib/instance_agent/codedeploy_plugin/application_specification/linux_permission_info.rb +121 -0
  23. data/lib/instance_agent/codedeploy_plugin/application_specification/mode_info.rb +66 -0
  24. data/lib/instance_agent/codedeploy_plugin/application_specification/range_info.rb +134 -0
  25. data/lib/instance_agent/codedeploy_plugin/application_specification/script_info.rb +27 -0
  26. data/lib/instance_agent/codedeploy_plugin/codedeploy_control.rb +72 -0
  27. data/lib/instance_agent/codedeploy_plugin/command_executor.rb +357 -0
  28. data/lib/instance_agent/codedeploy_plugin/command_poller.rb +146 -0
  29. data/lib/instance_agent/codedeploy_plugin/deployment_specification.rb +150 -0
  30. data/lib/instance_agent/codedeploy_plugin/hook_executor.rb +206 -0
  31. data/lib/instance_agent/codedeploy_plugin/install_instruction.rb +374 -0
  32. data/lib/instance_agent/codedeploy_plugin/installer.rb +143 -0
  33. data/lib/instance_agent/codedeploy_plugin/request_helper.rb +28 -0
  34. data/lib/instance_agent/config.rb +43 -0
  35. data/lib/instance_agent/log.rb +3 -0
  36. data/lib/instance_agent/platform.rb +17 -0
  37. data/lib/instance_agent/platform/linux_util.rb +57 -0
  38. data/lib/instance_agent/runner/child.rb +57 -0
  39. data/lib/instance_agent/runner/master.rb +103 -0
  40. data/lib/instance_metadata.rb +47 -0
  41. data/test/certificate_helper.rb +120 -0
  42. data/test/helpers/instance_agent_helper.rb +25 -0
  43. data/test/instance_agent/agent/base_test.rb +49 -0
  44. data/test/instance_agent/codedeploy_plugin/application_specification_test.rb +1710 -0
  45. data/test/instance_agent/codedeploy_plugin/codedeploy_control_test.rb +51 -0
  46. data/test/instance_agent/codedeploy_plugin/command_executor_test.rb +513 -0
  47. data/test/instance_agent/codedeploy_plugin/command_poller_test.rb +459 -0
  48. data/test/instance_agent/codedeploy_plugin/deployment_specification_test.rb +335 -0
  49. data/test/instance_agent/codedeploy_plugin/hook_executor_test.rb +250 -0
  50. data/test/instance_agent/codedeploy_plugin/install_instruction_test.rb +566 -0
  51. data/test/instance_agent/codedeploy_plugin/installer_test.rb +519 -0
  52. data/test/instance_agent/codedeploy_plugin/request_helper_test.rb +37 -0
  53. data/test/instance_agent/config_test.rb +64 -0
  54. data/test/instance_agent/runner/child_test.rb +87 -0
  55. data/test/instance_metadata_test.rb +97 -0
  56. data/test/test_helper.rb +16 -0
  57. data/vendor/gems/.codedeploy-commands-1.0.0.created.rid +1 -0
  58. data/vendor/gems/codedeploy-commands/apis/CodeDeployCommand.api.json +372 -0
  59. data/vendor/gems/codedeploy-commands/codedeploy-commands-1.0.0.gemspec +28 -0
  60. data/vendor/gems/codedeploy-commands/lib/aws/codedeploy_commands.rb +18 -0
  61. data/vendor/gems/codedeploy-commands/lib/aws/plugins/certificate_authority.rb +12 -0
  62. data/vendor/gems/codedeploy-commands/lib/aws/plugins/deploy_control_endpoint.rb +22 -0
  63. data/vendor/gems/process_manager/README.md +1 -0
  64. data/vendor/gems/process_manager/lib/blank.rb +153 -0
  65. data/vendor/gems/process_manager/lib/core_ext.rb +73 -0
  66. data/vendor/gems/process_manager/lib/process_manager.rb +49 -0
  67. data/vendor/gems/process_manager/lib/process_manager/child.rb +119 -0
  68. data/vendor/gems/process_manager/lib/process_manager/config.rb +112 -0
  69. data/vendor/gems/process_manager/lib/process_manager/log.rb +107 -0
  70. data/vendor/gems/process_manager/lib/process_manager/master.rb +322 -0
  71. data/vendor/gems/process_manager/process_manager-0.0.13.gemspec +42 -0
  72. data/vendor/specifications/aws-sdk-core-2.0.5.gemspec +39 -0
  73. data/vendor/specifications/builder-3.2.2.gemspec +29 -0
  74. data/vendor/specifications/codedeploy-commands-1.0.0.gemspec +28 -0
  75. data/vendor/specifications/gli-2.5.6.gemspec +51 -0
  76. data/vendor/specifications/jamespath-0.5.1.gemspec +35 -0
  77. data/vendor/specifications/little-plugger-1.1.3.gemspec +32 -0
  78. data/vendor/specifications/logging-1.8.1.gemspec +44 -0
  79. data/vendor/specifications/multi_json-1.7.7.gemspec +30 -0
  80. data/vendor/specifications/multi_json-1.8.4.gemspec +30 -0
  81. data/vendor/specifications/multi_xml-0.5.5.gemspec +30 -0
  82. data/vendor/specifications/process_manager-0.0.13.gemspec +42 -0
  83. data/vendor/specifications/simple_pid-0.2.1.gemspec +28 -0
  84. metadata +377 -0
@@ -0,0 +1,142 @@
1
+ module InstanceAgent
2
+ module CodeDeployPlugin
3
+ module ApplicationSpecification
4
+
5
+ class AppSpecValidationException < Exception; end
6
+ class ApplicationSpecification
7
+
8
+ attr_reader :version, :os, :hooks, :files, :permissions
9
+
10
+ def initialize(yaml_hash, opts = {})
11
+ @version = parse_version(yaml_hash['version'])
12
+ @os = parse_os(yaml_hash['os'])
13
+ @hooks = parse_hooks(yaml_hash['hooks'] || {})
14
+ @files = parse_files(yaml_hash['files'] || [])
15
+ @permissions = parse_permissions(yaml_hash['permissions'] || [])
16
+ end
17
+
18
+ def self.parse(app_spec_string)
19
+ new(YAML.load(app_spec_string))
20
+ end
21
+
22
+ private
23
+ def supported_versions()
24
+ [0.0]
25
+ end
26
+
27
+ def parse_version(version)
28
+ if !supported_versions.include?(version)
29
+ raise AppSpecValidationException, "unsupported version: #{version}"
30
+ end
31
+ version
32
+ end
33
+
34
+ def supported_oses()
35
+ InstanceAgent::Platform.util.supported_oses()
36
+ end
37
+
38
+ def parse_os(os)
39
+ if !supported_oses.include?(os)
40
+ raise AppSpecValidationException, "unsupported os: #{os}"
41
+ end
42
+ os
43
+ end
44
+
45
+ def parse_files(file_map_hash)
46
+ files = []
47
+ #loop through hash and create fileInfo representations
48
+ file_map_hash.each do |mapping|
49
+ files << FileInfo.new(mapping['source'], mapping['destination'])
50
+ end
51
+ files
52
+ end
53
+
54
+ def parse_hooks(hooks_hash)
55
+ temp_hooks_hash = Hash.new
56
+ hooks_hash.each_pair do |hook, scripts|
57
+ current_hook_scripts = []
58
+ scripts.each do |script|
59
+ if (script.has_key?('location'))
60
+ current_hook_scripts << InstanceAgent::CodeDeployPlugin::ApplicationSpecification::ScriptInfo.new(script['location'].strip,
61
+ {
62
+ :runas => script.has_key?('runas') ? script['runas'].strip : nil,
63
+ :timeout => script['timeout']
64
+ })
65
+ else
66
+ raise AppSpecValidationException, 'script provided without a location value'
67
+ end
68
+ end
69
+ temp_hooks_hash[hook] = current_hook_scripts
70
+ end
71
+ temp_hooks_hash
72
+ end
73
+
74
+ def parse_permissions(permissions_list)
75
+ permissions = []
76
+ #loop through list and create permissionsInfo representations
77
+ permissions_list.each do |permission|
78
+ if !permission.has_key?('object')
79
+ raise AppSpecValidationException, 'permission provided without a object value'
80
+ end
81
+ if @os.eql?('linux')
82
+ permissions << InstanceAgent::CodeDeployPlugin::ApplicationSpecification::LinuxPermissionInfo.new(permission['object'].strip,
83
+ {
84
+ :pattern => ('**'.eql?(permission['pattern']) || permission['pattern'].nil?) ? '**' : parse_simple_glob(permission['pattern']),
85
+ :except => parse_simple_glob_list(permission['except']),
86
+ :type => parse_type_list(permission['type']),
87
+ :owner => permission['owner'],
88
+ :group => permission['group'],
89
+ :mode => parse_mode(permission['mode']),
90
+ :acls => parse_acl(permission['acls']),
91
+ :context => parse_context(permission['context'])
92
+ })
93
+ else
94
+ raise AppSpecValidationException, 'permissions only supported with linux os currently'
95
+ end
96
+ end
97
+ permissions
98
+ end
99
+
100
+ #placeholder for parsing globs: we should verify that the glob is only including what we expect. For now just returning it as it is.
101
+ def parse_simple_glob(glob)
102
+ glob
103
+ end
104
+
105
+ def parse_simple_glob_list(glob_list)
106
+ temp_glob_list = []
107
+ (glob_list || []).each do |glob|
108
+ temp_glob_list << parse_simple_glob(glob)
109
+ end
110
+ temp_glob_list
111
+ end
112
+
113
+ def supported_types
114
+ ['file', 'directory']
115
+ end
116
+
117
+ def parse_type_list(type_list)
118
+ type_list ||= supported_types
119
+ type_list.each do |type|
120
+ if !supported_types.include?(type)
121
+ raise AppSpecValidationException, "assigning permissions to objects of type #{type} not supported"
122
+ end
123
+ end
124
+ type_list
125
+ end
126
+
127
+ def parse_mode(mode)
128
+ mode.nil? ? nil : InstanceAgent::CodeDeployPlugin::ApplicationSpecification::ModeInfo.new(mode)
129
+ end
130
+
131
+ def parse_acl(acl)
132
+ acl.nil? ? nil : InstanceAgent::CodeDeployPlugin::ApplicationSpecification::AclInfo.new(acl)
133
+ end
134
+
135
+ def parse_context(context)
136
+ context.nil? ? nil : InstanceAgent::CodeDeployPlugin::ApplicationSpecification::ContextInfo.new(context)
137
+ end
138
+ end
139
+
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,23 @@
1
+ module InstanceAgent
2
+ module CodeDeployPlugin
3
+ module ApplicationSpecification
4
+
5
+ #Helper Class for storing a context
6
+ class ContextInfo
7
+
8
+ attr_reader :user, :role, :type, :range
9
+
10
+ def initialize(context)
11
+ if context['type'].nil?
12
+ raise AppSpecValidationException, "invalid context type required #{context.inspect}"
13
+ end
14
+ @user = context['name']
15
+ @role = nil
16
+ @type = context['type']
17
+ @range = context['range'].nil? ? nil : RangeInfo.new(context['range'])
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ module InstanceAgent
2
+ module CodeDeployPlugin
3
+ module ApplicationSpecification
4
+
5
+ #Helper class for storing data parsed from file maps
6
+ class FileInfo
7
+
8
+ attr_reader :source, :destination
9
+
10
+ def initialize(source, destination, opts = {})
11
+ if(source.nil?)
12
+ raise AppSpecValidationException, 'File needs to have a source'
13
+ elsif (destination.nil?)
14
+ raise AppSpecValidationException, 'File needs to have a destination'
15
+ end
16
+ @source = source
17
+ @destination = destination
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,121 @@
1
+ module InstanceAgent
2
+ module CodeDeployPlugin
3
+ module ApplicationSpecification
4
+
5
+ #Helper Class for storing data parsed from permissions list
6
+ class LinuxPermissionInfo
7
+
8
+ attr_reader :object, :pattern, :except, :type, :owner, :group, :mode, :acls, :context
9
+
10
+ def initialize(object, opts = {})
11
+ object = object.to_s
12
+ if (object.empty?)
13
+ raise AppSpecValidationException, 'Permission needs a object value'
14
+ end
15
+ @object = object
16
+ @pattern = opts[:pattern] || "**"
17
+ @except = opts[:except] || []
18
+ @type = opts[:type] || ["file", "directory"]
19
+ @owner = opts[:owner]
20
+ @group = opts[:group]
21
+ @mode = opts[:mode]
22
+ @acls = opts[:acls]
23
+ @context = opts[:context]
24
+ end
25
+
26
+ def validate_file_permission()
27
+ if @type.include?("file")
28
+ if !"**".eql?(@pattern)
29
+ raise AppSpecValidationException, "Attempt to use pattern #{@pattern} when assigning permissions to file #{@object}"
30
+ end
31
+ if !@except.empty?
32
+ raise AppSpecValidationException, "Attempt to use except #{@except} when assigning permissions to file #{@object}"
33
+ end
34
+ end
35
+ end
36
+
37
+ def validate_file_acl(object)
38
+ if !@acls.nil?
39
+ default_acl = @acls.get_default_ace
40
+ if !default_acl.nil?
41
+ raise "Attempt to set default acl #{default_acl} on file #{object}"
42
+ end
43
+ end
44
+ end
45
+
46
+ def matches_pattern?(name)
47
+ name = name.chomp(File::SEPARATOR)
48
+ base_object = sanitize_dir_path(@object)
49
+ if !base_object.end_with?(File::SEPARATOR)
50
+ base_object = base_object + File::SEPARATOR
51
+ end
52
+ if name.start_with?(base_object)
53
+ if ("**".eql?(@pattern))
54
+ return true
55
+ end
56
+ rel_name = name[base_object.length..name.length]
57
+ return matches_simple_glob(rel_name, @pattern)
58
+ end
59
+ false
60
+ end
61
+
62
+ def matches_except?(name)
63
+ name = name.chomp(File::SEPARATOR)
64
+ base_object = sanitize_dir_path(@object)
65
+ if !base_object.end_with?(File::SEPARATOR)
66
+ base_object = base_object + File::SEPARATOR
67
+ end
68
+ if name.start_with?(base_object)
69
+ rel_name = name[base_object.length..name.length]
70
+ @except.each do |item|
71
+ if matches_simple_glob(rel_name, item)
72
+ return true
73
+ end
74
+ end
75
+ end
76
+ false
77
+ end
78
+
79
+ private
80
+ def matches_simple_glob(name, pattern)
81
+ if name.include?(File::SEPARATOR)
82
+ return false
83
+ end
84
+ options = expand(pattern.chars.entries)
85
+ name.chars.each do |char|
86
+ new_options = []
87
+ options.each do |option|
88
+ if option[0].eql?("*")
89
+ new_options.concat(expand(option))
90
+ elsif option[0].eql?(char)
91
+ option.shift
92
+ new_options.concat(expand(option))
93
+ end
94
+ end
95
+ options = new_options
96
+ if (options.include?(["*"]))
97
+ return true
98
+ end
99
+ end
100
+ options.include?([])
101
+ end
102
+
103
+ private
104
+ def expand(option)
105
+ previous_option = nil
106
+ while "*".eql?(option[0]) do
107
+ previous_option = Array.new(option)
108
+ option.shift
109
+ end
110
+ previous_option.nil? ? [option] : [previous_option, option]
111
+ end
112
+
113
+ private
114
+ def sanitize_dir_path(path)
115
+ File.expand_path(path)
116
+ end
117
+ end
118
+
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,66 @@
1
+ module InstanceAgent
2
+ module CodeDeployPlugin
3
+ module ApplicationSpecification
4
+
5
+ #Helper Class for storing mode of a file
6
+ class ModeInfo
7
+
8
+ attr_reader :mode
9
+ attr_reader :world, :world_readable, :world_writable, :world_executable
10
+ attr_reader :group, :group_readable, :group_writable, :group_executable
11
+ attr_reader :owner, :owner_readable, :owner_writable, :owner_executable
12
+ attr_reader :setuid, :setgid, :sticky
13
+
14
+ def initialize(mode)
15
+ mode = mode.to_s
16
+ while mode.length < 3 do
17
+ mode = "0" + mode;
18
+ end
19
+ if mode.length > 4
20
+ raise AppSpecValidationException, "permission mode length incorrect: #{mode}"
21
+ end
22
+ mode.each_char do |char|
23
+ if (char.ord < '0'.ord) || (char.ord > '7'.ord)
24
+ raise AppSpecValidationException, "invalid character #{char} in permission mode #{mode}"
25
+ end
26
+ end
27
+ @mode = mode
28
+ mode_array = mode.reverse.chars.entries
29
+
30
+ @world = mode_array[0]
31
+ world_bits = to_bits(@world.to_i, 3)
32
+ @world_readable = (world_bits[0] == 1)
33
+ @world_writable = (world_bits[1] == 1)
34
+ @world_executable = (world_bits[2] == 1)
35
+
36
+ @group = mode_array[1]
37
+ group_bits = to_bits(@group.to_i, 3)
38
+ @group_readable = (group_bits[0] == 1)
39
+ @group_writable = (group_bits[1] == 1)
40
+ @group_executable = (group_bits[2] == 1)
41
+
42
+ @owner = mode_array[2]
43
+ owner_bits = to_bits(@owner.to_i, 3)
44
+ @owner_readable = (owner_bits[0] == 1)
45
+ @owner_writable = (owner_bits[1] == 1)
46
+ @owner_executable = (owner_bits[2] == 1)
47
+
48
+ special = (mode_array.length > 3) ? mode_array[3]: '0'
49
+ special_bits = to_bits(special.to_i, 3)
50
+ @setuid = (special_bits[0] == 1)
51
+ @setgid = (special_bits[1] == 1)
52
+ @sticky = (special_bits[2] == 1)
53
+ end
54
+
55
+ def to_bits(num, min_size)
56
+ bits = Array.new(min_size, 0)
57
+ num_bits = num.to_s(2).split("")
58
+ diff = [0, min_size - num_bits.length].max
59
+ num_bits.map.with_index {|n,i| bits[i+diff] = n.to_i}
60
+ bits
61
+ end
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,134 @@
1
+ module InstanceAgent
2
+ module CodeDeployPlugin
3
+ module ApplicationSpecification
4
+
5
+ #Helper Class for storing the range of a context
6
+ class RangeInfo
7
+
8
+ attr_reader :low_sensitivity, :high_sensitivity, :categories
9
+
10
+ def initialize(range)
11
+ parts = ensure_parts(range, ":")
12
+ sensitivity_parts = ensure_parts(parts[0], "-")
13
+ @low_sensitivity = getSensitivityNumber(sensitivity_parts[0])
14
+ if sensitivity_parts.length == 2
15
+ @high_sensitivity = getSensitivityNumber(sensitivity_parts[1])
16
+ if @high_sensitivity < @low_sensitivity
17
+ raise AppSpecValidationException, "invalid sensitivity range in #{range}"
18
+ end
19
+ else
20
+ @high_sensitivity = @low_sensitivity
21
+ end
22
+ if parts.length == 2
23
+ @categories = get_category_numbers(parts[1].split(","))
24
+ end
25
+ end
26
+
27
+ def ensure_parts(input, split_on)
28
+ num_parts = 1
29
+ if input.include?(split_on)
30
+ num_parts = 2
31
+ end
32
+ parts = input.split(split_on, 2)
33
+ if parts.length != num_parts
34
+ raise AppSpecValidationException, "invalid range part #{input}"
35
+ end
36
+ parts.each do |part|
37
+ if part.nil? || part.eql?('')
38
+ raise AppSpecValidationException, "invalid range part #{input}"
39
+ end
40
+ end
41
+ parts
42
+ end
43
+
44
+ def getSensitivityNumber(sensitivity)
45
+ if sensitivity.nil? || sensitivity.length < 2 || !sensitivity.start_with?('s')
46
+ raise AppSpecValidationException, "invalid sensitivity #{sensitivity}"
47
+ end
48
+ s_level = sensitivity.sub('s', '')
49
+ s_level.chars.each do |digit|
50
+ if (digit.ord < '0'.ord) || (digit.ord > '9'.ord)
51
+ raise AppSpecValidationException, "invalid sensitivity #{sensitivity}"
52
+ end
53
+ end
54
+ s_level.to_i
55
+ end
56
+
57
+ def get_category_number(category)
58
+ if category.nil? || category.length < 2 || !category.start_with?('c')
59
+ raise AppSpecValidationException, "invalid category #{category}"
60
+ end
61
+ c_level = category.sub('c', '')
62
+ c_level.chars.each do |digit|
63
+ if (digit.ord < '0'.ord) || (digit.ord > '9'.ord)
64
+ raise AppSpecValidationException, "invalid category #{category}"
65
+ end
66
+ end
67
+ level = c_level.to_i
68
+ if level > 1023
69
+ raise AppSpecValidationException, "invalid category #{category}"
70
+ end
71
+ level
72
+ end
73
+
74
+ def get_category_range(range)
75
+ low = get_category_number(range[0])
76
+ high = get_category_number(range[1])
77
+ if (high < low)
78
+ raise AppSpecValidationException, "invalid category range #{range[0]}.#{range[1]}"
79
+ end
80
+ (low..high).to_a
81
+ end
82
+
83
+ def get_category_numbers(parts)
84
+ temp_categories = [];
85
+ parts.each do |part|
86
+ if part.include? "."
87
+ temp_categories.concat get_category_range(ensure_parts(part, "."))
88
+ else
89
+ temp_categories << get_category_number(part)
90
+ end
91
+ end
92
+ if !temp_categories.sort!.uniq!.nil?
93
+ raise AppSpecValidationException, "duplicate categories"
94
+ end
95
+ temp_categories
96
+ end
97
+
98
+ # format s#[-s#][:c#[.c#](,c#[.c#])*] (# means a number)
99
+ def get_range
100
+ range = "s" + @low_sensitivity.to_s
101
+ if (@low_sensitivity != @high_sensitivity)
102
+ range = range + "-s" + @high_sensitivity.to_s
103
+ end
104
+ if @categories
105
+ range = range + ":"
106
+ index = 0
107
+ while index < @categories.length
108
+ if (index != 0)
109
+ range = range + ","
110
+ end
111
+
112
+ low = @categories[index]
113
+ low_index = index
114
+ high = @categories[index]
115
+ index += 1
116
+ while (@categories[index] == low + (index - low_index))
117
+ high += 1
118
+ index += 1
119
+ end
120
+
121
+ if (low == high)
122
+ range = range + "c" + low.to_s
123
+ else
124
+ range = range + "c" + low.to_s + ".c" + high.to_s
125
+ end
126
+ end
127
+ end
128
+ range
129
+ end
130
+ end
131
+
132
+ end
133
+ end
134
+ end