CloudyScripts 0.0.11 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,206 +1,148 @@
1
- require "help/script_execution_state"
2
- require "scripts/ec2/ec2_script"
3
- require "help/remote_command_handler"
4
- require "help/dm_crypt_helper"
5
- require "AWS"
6
-
7
- # Script to Encrypt an EC2 Storage (aka Elastic Block Storage)
8
- #
9
- class DmEncrypt < Ec2Script
10
- # dependencies: tools that need to be installed to make things work
11
- TOOLS = ["cryptsetup"]
12
- # the parameters for which
13
- CHECK = ["cryptsetup"]
14
-
15
- # Input parameters
16
- # * aws_access_key => the Amazon AWS Access Key (see Your Account -> Security Credentials)
17
- # * aws_secret_key => the Amazon AWS Secret Key
18
- # * ip_address => IP Address of the machine to connect to
19
- # * ssh_key_file => Path of the keyfile used to connect to the machine (optional, otherwise: ssh_key_data)
20
- # * ssh_key_data => Key information (optional, otherwise: ssh_key_file)
21
- # * device => Path of the device to encrypt
22
- # * device_name => Name of the Device to encrypt
23
- # * storage_path => Path on which the encrypted device is mounted
24
- # * paraphrase => paraphrase used for encryption
25
- # * remote_command_handler => object that allows to connect via ssh and execute commands (optional)
26
- # * ec2_api_handler => object that allows to access the EC2 API (optional)
27
- # * ec2_api_server => server to connect to (option, default is us-east-1.ec2.amazonaws.com)
28
- #
29
-
30
- def initialize(input_params)
31
- super(input_params)
32
- end
33
-
34
- # Executes the script.
35
- def start_script
36
- begin
37
- # optional parameters and initialization
38
- if @input_params[:ec2_api_server] == nil
39
- @input_params[:ec2_api_server] = "us-east-1.ec2.amazonaws.com"
40
- end
41
- if @input_params[:remote_command_handler] == nil
42
- @input_params[:remote_command_handler] = RemoteCommandHandler.new
43
- end
44
- if @input_params[:ec2_api_handler] == nil
45
- @input_params[:ec2_api_handler] = AWS::EC2::Base.new(:access_key_id => @input_params[:aws_access_key],
46
- :secret_access_key => @input_params[:aws_secret_key], :server => @input_params[:ec2_api_server])
47
- end
48
- @input_params[:script] = self
49
- # start state machine
50
- current_state = DmEncryptState.load_state(@input_params)
51
- @state_change_listeners.each() {|listener|
52
- current_state.register_state_change_listener(listener)
53
- }
54
- end_state = current_state.start_state_machine()
55
- if end_state.failed?
56
- @result[:failed] = true
57
- @result[:failure_reason] = current_state.end_state.failure_reason
58
- @result[:end_state] = current_state.end_state
59
- else
60
- @result[:failed] = false
61
- end
62
- rescue Exception => e
63
- @logger.warn "exception during encryption: #{e}"
64
- @logger.info e.backtrace.join("\n")
65
- err = e.to_s
66
- err += " (in #{current_state.end_state.to_s})" unless current_state == nil
67
- @result[:failed] = true
68
- @result[:failure_reason] = err
69
- @result[:end_state] = current_state.end_state unless current_state == nil
70
- ensure
71
- begin
72
- @input_params[:remote_command_handler].disconnect
73
- rescue Exception => e2
74
- end
75
- end
76
- #
77
- @result[:done] = true
78
- end
79
-
80
- # Returns a hash with the following information:
81
- # :done => if execution is done
82
- #
83
- def get_execution_result
84
- @result
85
- end
86
-
87
- private
88
-
89
- # Here begins the state machine implementation
90
- class DmEncryptState < ScriptExecutionState
91
-
92
- def self.load_state(context)
93
- InitialState.new(context)
94
- end
95
- end
96
-
97
- # Starting state. Tries to connect via ssh.
98
- class InitialState < DmEncryptState
99
- def enter
100
- connect()
101
- end
102
-
103
- private
104
-
105
- def connect()
106
- @context[:script].post_message("going to connect to #{@context[:ip_address]}...")
107
- @logger.debug "InitialState.connect"
108
- if @context[:ssh_key_file] != nil
109
- @context[:remote_command_handler].connect_with_keyfile(@context[:ip_address], @context[:ssh_key_file])
110
- elsif @context[:ssh_key_data] != nil
111
- @context[:remote_command_handler].connect(@context[:ip_address], "root", @context[:ssh_key_data])
112
- else
113
- raise Exception.new("no key information specified")
114
- end
115
- @context[:result][:os] = @context[:remote_command_handler].retrieve_os()
116
- @context[:script].post_message("connection successful, OS = #{@context[:result][:os]}")
117
- ConnectedState.new(@context)
118
- end
119
- end
120
-
121
- # Connected via SSH. Tries to install dm-encrypt.#TODO: depends on OS
122
- class ConnectedState < DmEncryptState
123
- def enter
124
- install_tools()
125
- end
126
-
127
- private
128
- def install_tools
129
- @context[:script].post_message("check if the system has the cryptset-package installed")
130
- @logger.debug "ConnectedState.install_tools"
131
- if !tools_installed?
132
- @context[:script].post_message("cryptset-package not installed. Going to install it...")
133
- TOOLS.each() {|tool|
134
- @context[:remote_command_handler].install(tool)
135
- }
136
- end
137
- if !@context[:remote_command_handler].remote_execute("modprobe dm_crypt")
138
- raise Exception.new("dm-crypt module missing")
139
- end
140
- if tools_installed?
141
- @context[:script].post_message("cryptset-package is available")
142
- @logger.debug "system says that tools are installed"
143
- ToolInstalledState.new(@context)
144
- else
145
- FailedState.new(@context, "Installation of Tools failed", ConnectedState.new(@context))
146
- end
147
- end
148
-
149
- def tools_installed?
150
- CHECK.each() {|tool|
151
- if !@context[:remote_command_handler].tools_installed?(tool)
152
- return false
153
- end
154
- }
155
- true
156
- end
157
- end
158
-
159
- # Connected and Tools installed. Start encryption.
160
- class ToolInstalledState < DmEncryptState
161
- def enter
162
- create_encrypted_volume()
163
- end
164
-
165
- private
166
- def create_encrypted_volume
167
- @context[:script].post_message("going to encrypt device #{@context[:device]} "+
168
- "named '#{@context[:device_name]}' and mount it as #{@context[:storage_path]}...")
169
- @logger.debug "ToolInstalledState.create_encrypted_volume"
170
- @context[:remote_command_handler].encrypt_storage(@context[:device_name],
171
- @context[:paraphrase], @context[:device], @context[:storage_path])
172
- @context[:script].post_message("device #{@context[:device]} is encrypted and mounted")
173
- MountedAndActivatedState.new(@context)
174
- end
175
-
176
- def calc_device_name
177
- dev = @context[:device_name].gsub(/[-]/,"--")
178
- "/dev/mapper/vg--#{dev}-lv--#{dev}"
179
- end
180
-
181
- end
182
-
183
- # The encrypted storages is mounted and activated. Cleanup and done.
184
- class MountedAndActivatedState < DmEncryptState
185
- def enter
186
- cleanup()
187
- end
188
-
189
- private
190
- def cleanup()
191
- @context[:script].post_message("disconnecting...")
192
- @logger.debug "MountedAndActivatedState.cleanup"
193
- @context[:remote_command_handler].disconnect()
194
- @context[:script].post_message("done")
195
- DoneState.new(@context)
196
- end
197
-
198
- end
199
-
200
- class DoneState < DmEncryptState
201
- def done?
202
- true
203
- end
204
- end
205
-
1
+ require "help/script_execution_state"
2
+ require "scripts/ec2/ec2_script"
3
+ require "help/remote_command_handler"
4
+ require "help/dm_crypt_helper"
5
+ require "AWS"
6
+
7
+ # Script to Encrypt an EC2 Storage (aka Elastic Block Storage)
8
+ #
9
+ class DmEncrypt < Ec2Script
10
+ # dependencies: tools that need to be installed to make things work
11
+ TOOLS = ["cryptsetup"]
12
+ # the parameters for which
13
+ CHECK = ["cryptsetup"]
14
+
15
+ # Input parameters
16
+ # * aws_access_key => the Amazon AWS Access Key (see Your Account -> Security Credentials)
17
+ # * aws_secret_key => the Amazon AWS Secret Key
18
+ # * ip_address => IP Address of the machine to connect to
19
+ # * ssh_key_file => Path of the keyfile used to connect to the machine (optional, otherwise: ssh_key_data)
20
+ # * ssh_key_data => Key information (optional, otherwise: ssh_key_file)
21
+ # * device => Path of the device to encrypt
22
+ # * device_name => Name of the Device to encrypt
23
+ # * storage_path => Path on which the encrypted device is mounted
24
+ # * paraphrase => paraphrase used for encryption
25
+ # * remote_command_handler => object that allows to connect via ssh and execute commands (optional)
26
+ # * ec2_api_handler => object that allows to access the EC2 API (optional)
27
+ # * ec2_api_server => server to connect to (option, default is us-east-1.ec2.amazonaws.com)
28
+ #
29
+
30
+ def initialize(input_params)
31
+ super(input_params)
32
+ end
33
+
34
+ def check_input_parameters()
35
+ if @input_params[:ec2_api_server] == nil
36
+ @input_params[:ec2_api_server] = "us-east-1.ec2.amazonaws.com"
37
+ end
38
+ if @input_params[:remote_command_handler] == nil
39
+ @input_params[:remote_command_handler] = RemoteCommandHandler.new
40
+ end
41
+ if @input_params[:ec2_api_handler] == nil
42
+ @input_params[:ec2_api_handler] = AWS::EC2::Base.new(:access_key_id => @input_params[:aws_access_key],
43
+ :secret_access_key => @input_params[:aws_secret_key], :server => @input_params[:ec2_api_server])
44
+ end
45
+ end
46
+
47
+ def load_initial_state()
48
+ DmEncryptState.load_state(@input_params)
49
+ end
50
+
51
+ private
52
+
53
+ # Here begins the state machine implementation
54
+ class DmEncryptState < ScriptExecutionState
55
+
56
+ def self.load_state(context)
57
+ InitialState.new(context)
58
+ end
59
+ end
60
+
61
+ # Starting state. Tries to connect via ssh.
62
+ class InitialState < DmEncryptState
63
+ def enter
64
+ connect()
65
+ install_tools()
66
+ end
67
+
68
+ private
69
+
70
+ def install_tools
71
+ @context[:script].post_message("check if the system has the cryptset-package installed")
72
+ @logger.debug "ConnectedState.install_tools"
73
+ if !tools_installed?
74
+ @context[:script].post_message("cryptset-package not installed. Going to install it...")
75
+ TOOLS.each() {|tool|
76
+ @context[:remote_command_handler].install(tool)
77
+ }
78
+ end
79
+ if !@context[:remote_command_handler].remote_execute("modprobe dm_crypt")
80
+ raise Exception.new("dm-crypt module missing")
81
+ end
82
+ if tools_installed?
83
+ @context[:script].post_message("cryptset-package is available")
84
+ @logger.debug "system says that tools are installed"
85
+ ToolInstalledState.new(@context)
86
+ else
87
+ FailedState.new(@context, "Installation of Tools failed", ConnectedState.new(@context))
88
+ end
89
+ end
90
+
91
+ def tools_installed?
92
+ CHECK.each() {|tool|
93
+ if !@context[:remote_command_handler].tools_installed?(tool)
94
+ return false
95
+ end
96
+ }
97
+ true
98
+ end
99
+ end
100
+
101
+ # Connected and Tools installed. Start encryption.
102
+ class ToolInstalledState < DmEncryptState
103
+ def enter
104
+ create_encrypted_volume()
105
+ end
106
+
107
+ private
108
+ def create_encrypted_volume
109
+ @context[:script].post_message("going to encrypt device #{@context[:device]} "+
110
+ "named '#{@context[:device_name]}' and mount it as #{@context[:storage_path]}...")
111
+ @logger.debug "ToolInstalledState.create_encrypted_volume"
112
+ @context[:remote_command_handler].encrypt_storage(@context[:device_name],
113
+ @context[:paraphrase], @context[:device], @context[:storage_path])
114
+ @context[:script].post_message("device #{@context[:device]} is encrypted and mounted")
115
+ MountedAndActivatedState.new(@context)
116
+ end
117
+
118
+ def calc_device_name
119
+ dev = @context[:device_name].gsub(/[-]/,"--")
120
+ "/dev/mapper/vg--#{dev}-lv--#{dev}"
121
+ end
122
+
123
+ end
124
+
125
+ # The encrypted storages is mounted and activated. Cleanup and done.
126
+ class MountedAndActivatedState < DmEncryptState
127
+ def enter
128
+ cleanup()
129
+ end
130
+
131
+ private
132
+ def cleanup()
133
+ @context[:script].post_message("disconnecting...")
134
+ @logger.debug "MountedAndActivatedState.cleanup"
135
+ @context[:remote_command_handler].disconnect()
136
+ @context[:script].post_message("done")
137
+ DoneState.new(@context)
138
+ end
139
+
140
+ end
141
+
142
+ class DoneState < DmEncryptState
143
+ def done?
144
+ true
145
+ end
146
+ end
147
+
206
148
  end
@@ -0,0 +1,153 @@
1
+ require "help/script_execution_state"
2
+ require "scripts/ec2/ec2_script"
3
+ require "help/remote_command_handler"
4
+ require "help/dm_crypt_helper"
5
+ require "AWS"
6
+
7
+ # Script to download a specific snapshot as ZIP
8
+ # * create a specific instance (with Apache Server),
9
+ # * create a volume based on the snapshot
10
+ # * attach the volume
11
+ # * create a XSF-file-system
12
+ # * freeze the file-system
13
+ # * zip the file-system and copy it to the apache folder
14
+ # * wait 5 minutes (now the zip-file can be downloaded)
15
+ # * alternatively: copy it to S3 and make it downloadable
16
+ # * alternatively: copy it to an FTP server
17
+ #
18
+ class DownloadSnapshot < Ec2Script
19
+ # context information needed
20
+ # * the EC2 credentials (see #Ec2Script)
21
+ # * ami_id: the ID of the AMI to be started to perform the operations and to run the web-server for download
22
+ # * security_group_name => name of the security group used to start the AMI (should open ports for SSH and HTTP)
23
+ # * ssh_key_data => Key information for the security group that starts the AMI [if not set, use ssh_key_files]
24
+ # * ssh_key_files => Key information for the security group that starts the AMI
25
+ # * snapshot_id => The ID of the snapshot to be downloaded
26
+ # * wait_time (optional, default = 300) => time in sec during which the zipped snapshot is downloadable
27
+ # * zip_file_dest (optional, default = '/var/www/html') => path of directory where the zipped volume is copied to
28
+ # * zip_file_name (option, default = 'download') => name of the zip-file to download
29
+ def initialize(input_params)
30
+ super(input_params)
31
+ end
32
+
33
+ def check_input_parameters()
34
+ if @input_params[:temp_device_name] == nil
35
+ @input_params[:temp_device_name] = "/dev/sdj"
36
+ end
37
+ if @input_params[:zip_file_dest] == nil
38
+ @input_params[:zip_file_dest] = "/var/www/html/"
39
+ end
40
+ if @input_params[:zip_file_name] == nil
41
+ @input_params[:zip_file_name] = "download"
42
+ end
43
+ if @input_params[:wait_time] == nil
44
+ @input_params[:wait_time] = 300
45
+ end
46
+ end
47
+
48
+ # Load the initial state for the script.
49
+ # Abstract method to be implemented by extending classes.
50
+ def load_initial_state()
51
+ DownloadSnapshotState.load_state(@input_params)
52
+ end
53
+
54
+ private
55
+
56
+ # Here begins the state machine implementation
57
+ class DownloadSnapshotState < ScriptExecutionState
58
+
59
+ def self.load_state(context)
60
+ InitialState.new(context)
61
+ end
62
+ end
63
+
64
+ #Connected.
65
+ # Start state. First thing to do is to launch the instance.
66
+ class InitialState < DownloadSnapshotState
67
+ def enter
68
+ launch_instance()
69
+ InstanceLaunchedState.new(context)
70
+ end
71
+ end
72
+
73
+ # Instance Launched. Create a volume based on the snapshot.
74
+ class InstanceLaunchedState < DownloadSnapshotState
75
+ def enter
76
+ create_volume_from_snapshot()
77
+ VolumeCreated.new(@context)
78
+ end
79
+
80
+ end
81
+
82
+ # Volume created. Attach it.
83
+ class VolumeCreated < DownloadSnapshotState
84
+ def enter
85
+ attach_volume()
86
+ VolumeAttached.new(@context)
87
+ end
88
+ end
89
+
90
+ # Volume attached. Create a file-system and mount it.
91
+ class VolumeAttached < DownloadSnapshotState
92
+ def enter
93
+ connect()
94
+ create_fs()
95
+ FileSystemCreated.new(@context)
96
+ end
97
+ end
98
+
99
+ # File system created. Mount it.
100
+ class FileSystemCreated < DownloadSnapshotState
101
+ def enter
102
+ mount_fs()
103
+ FileSystemMounted.new(@context)
104
+ end
105
+
106
+ end
107
+
108
+ # File System mounted. Zip the complete directory on the EBS.
109
+ class FileSystemMounted < DownloadSnapshotState
110
+ def enter
111
+ zip_volume()
112
+ VolumeZippedAndDownloadableState.new(@context)
113
+ end
114
+
115
+ end
116
+
117
+ # Volume is zipped and downloadable. Wait 5 minutes.
118
+ class VolumeZippedAndDownloadableState < DownloadSnapshotState
119
+ def enter
120
+ wait_some_time()
121
+ end
122
+
123
+ def get_link
124
+ "http://#{@context[:dns_name]}/#{@context[:zip_file_name]}.zip"
125
+ end
126
+
127
+ private
128
+
129
+ def wait_some_time
130
+ @context[:script].post_message("The snapshot can be downloaded during #{@context[:wait_time]} seconds from link: #{get_link()}")
131
+ sleep(@context[:wait_time])
132
+ DownloadStoppedState.new(@context)
133
+ end
134
+ end
135
+
136
+ # Snapshot can no longer be downloaded. Shut down the instance.
137
+ class DownloadStoppedState < DownloadSnapshotState
138
+ def enter
139
+ shut_down_instance()
140
+ InstanceShutDown.new(@context)
141
+ end
142
+
143
+ end
144
+
145
+ # Instance is shut down. Delete the volume created.
146
+ class InstanceShutDown < DownloadSnapshotState
147
+ def enter
148
+ delete_volume()
149
+ Done.new(@context)
150
+ end
151
+ end
152
+
153
+ end