---
conf/custom_template.tdl | 5 +-
conf/deploy | 6 -
conf/migrate | 6 -
conf/post | 6 +
recipes/aeolus/interactive.rb | 232 ++++++++++++++++----------
recipes/aeolus/manifests/conductor.pp | 10 +
recipes/aeolus/manifests/init.pp | 1 +
recipes/aeolus/manifests/profiles/deploy.pp | 10 -
recipes/aeolus/manifests/profiles/migrate.pp | 9 -
recipes/aeolus/manifests/profiles/post.pp | 10 +
recipes/snap/manifests/init.pp | 14 ++
11 files changed, 190 insertions(+), 119 deletions(-)
delete mode 100644 conf/deploy
delete mode 100644 conf/migrate
create mode 100644 conf/post
delete mode 100644 recipes/aeolus/manifests/profiles/deploy.pp
delete mode 100644 recipes/aeolus/manifests/profiles/migrate.pp
create mode 100644 recipes/aeolus/manifests/profiles/post.pp
create mode 100644 recipes/snap/manifests/init.pp
diff --git a/conf/custom_template.tdl b/conf/custom_template.tdl
index 3a7c1ff..7b26d1f 100644
--- a/conf/custom_template.tdl
+++ b/conf/custom_template.tdl
@@ -10,13 +10,14 @@
</install>
</os>
<repositories>
- <repository name="custom">
- <
url>http://repos.fedorapeople.org/repos/aeolus/demo/webapp/</url>
+ <repository name="aeolus_exipiremental">
+ <
url>http://yum.morsi.org/aeolus/</url>
<signed>false</signed>
</repository>
<!--AEOLUS_REPO_DATA-->
</repositories>
<packages>
+ <package name='snap' /> <!-- allows us to backup / restore system
snapshots -->
<!--AEOLUS_PACKAGE_DATA-->
</packages>
</template>
diff --git a/conf/deploy b/conf/deploy
deleted file mode 100644
index 69d52a9..0000000
--- a/conf/deploy
+++ /dev/null
@@ -1,6 +0,0 @@
----
-parameters:
- enable_https: true
- enable_security: false
-classes:
-- aeolus::profiles::deploy
diff --git a/conf/migrate b/conf/migrate
deleted file mode 100644
index 88f4eb4..0000000
--- a/conf/migrate
+++ /dev/null
@@ -1,6 +0,0 @@
----
-parameters:
- enable_https: true
- enable_security: false
-classes:
-- aeolus::profiles::migrate
diff --git a/conf/post b/conf/post
new file mode 100644
index 0000000..e18b3d5
--- /dev/null
+++ b/conf/post
@@ -0,0 +1,6 @@
+---
+parameters:
+ enable_https: true
+ enable_security: false
+classes:
+- aeolus::profiles::post
diff --git a/recipes/aeolus/interactive.rb b/recipes/aeolus/interactive.rb
index 0d2645a..c027c81 100644
--- a/recipes/aeolus/interactive.rb
+++ b/recipes/aeolus/interactive.rb
@@ -5,9 +5,9 @@ class AeolusConfig
@@providers ||= []
end
- def self.providers<<(provider_name)
+ def self.providers<<(name, type, username, password)
@@providers ||= []
- @@providers << provider_name
+ @@providers << [name, type, username, password]
end
end
@@ -18,6 +18,70 @@ end
###############################################################
+def aeolus_provider(options = {})
+ provider_name = options[:provider_name]
+ provider_driver = options[:provider_driver]
+ account_username = options[:account_username]
+ account_password = options[:account_password]
+
+ provider = options[:provider]
+ account = options[:account]
+
+ "aeolus::conductor::provider{#{provider_name}:\n" +
+ " deltacloud_driver =>
'#{provider_driver}',\n" +
+ " url =>
'http://localhost:3002/api',\n" +
+ provider.collect { |k,v| " #{k} =>
'#{v}'" }.join(",\n") +
+ " require =>
Aeolus::Conductor::Login['admin'] }\n" +
+ "aeolus::conductor::provider::account{#{account_username}:\n" +
+ " provider =>
'#{provider_name}',\n" +
+ " type =>
'#{provider_driver}',\n" +
+ " username =>
'#{account_username}',\n" +
+ " password =>
'#{account_password}',\n" +
+ account.collect { |k,v| " #{k} =>
'#{v}'" }.join(",\n") +
+ " require =>
Aeolus::Conductor::Provider['#{provider_name}'] }\n\n"
+
+end
+
+def aeolus_image(options = {})
+ name = options[:name]
+ provider = options[:provider]
+ provider_type = options[:provider_type]
+
+ "aeolus::image{#{provider}-#{name}:\n" +
+ " target => '#{provider_type}',\n" +
+ " template => 'custom_template.tdl',\n" +
+ " provider => '#{provider}',\n" +
+ " hwp => '#{provider_type == :rackspace ? 'hwp2' :
'hwp1' }',\n" +
+ " require => [Aeolus::Conductor::Provider::Account['#{name}'],
Aeolus::Conductor::Hwp['hwp1', 'hwp2']] }\n\n"
+end
+
+def aeolus_terminate_instance(options = {})
+ name = options[:name]
+
+ "aeolus::instance::terminate{#{name}:\n" +
+ " require => [Aeolus::Conductor::Login['admin']] }\n\n"
+end
+
+def aeolus_instance_snapshot(options = {})
+ ip_address = options[:ip_address]
+ key = options[:ssh_key]
+
+ "snap::snapshot{#{ip_address}:\n" +
+ " ssh_key => '#{key}',\n" +
+ " destination => '/tmp/snap-#{ip_address}.tgz'}\n\n"
+end
+
+def aeolus_instance_restore(options = {})
+ ip_address = options[:ip_address]
+ key = options[:ssh_key]
+
+ "snap::restore{#{ip_address}:\n" +
+ " ssh_key => '#{key}',\n" +
+ " source => '/tmp/snap-#{ip_address}.tgz'}\n\n"
+end
+
+###############################################################
+
def interactive_installer
NODE_YAML='/etc/aeolus-configure/nodes/custom'
PROFILE_RECIPE='/usr/share/aeolus-configure/modules/aeolus/manifests/profiles/custom.pp'
@@ -48,15 +112,13 @@ def interactive_installer
"- aeolus::iwhd"
end
end
-
- profile=''
- profile_requires = []
- profile_packages = ''
- profile_repos = ''
-
+
+ profile, profile_requires = '', ''
+
if install_components.include? "- aeolus::conductor"
- provider_port = 3001
while clear_screen && agree("Add provider (y/n)? ")
+ account_name, account_password, provider, account = nil, nil, {}, {}
+
name = ask("Cloud provider label: ")
type = choose do |menu|
menu.prompt = "Cloud provider type: "
@@ -66,73 +128,41 @@ def interactive_installer
menu.choice :rhevm
menu.choice :vsphere
end
- AeolusConfig.providers << [name,type]
if type == :mock
- profile += "aeolus::provider{#{name}:\n" +
- " type => 'mock',\n" +
- " port => '#{provider_port += 1}',\n" +
- " require => Aeolus::Conductor::Login['admin']
}\n\n" +
- "aeolus::conductor::provider::account{#{name}:\n" +
- " provider => 'mock',\n" +
- " type => 'mock',\n" +
- " username => 'mockuser',\n" +
- " password => 'mockpassword',\n" +
- " require => Aeolus::Provider['#{name}']
}\n\n"
- profile_requires << "Aeolus::Provider['#{name}']"
<<
-
"Aeolus::Conductor::Provider::Account['#{name}']"
+ account_name = 'mockuser'
+ account_password = 'mockpassword'
elsif type == :rackspace
- username = ask("Rackspace Username: ")
- api_key = ask("Rackspace API Key: "){ |q| q.echo = false }
- profile += "aeolus::provider{#{name}:\n" +
- " type => 'rackspace',\n" +
- " port => '#{provider_port += 1}',\n" +
- " require => Aeolus::Conductor::Login['admin']
}\n\n" +
- "aeolus::conductor::provider::account{#{name}:\n" +
- " provider => '#{name}',\n" +
- " type => 'rackspace',\n" +
- " username => '#{username}',\n" +
- " password => '#{api_key}',\n" +
- " require => Aeolus::Provider['#{name}']
}\n\n"
- profile_requires << "Aeolus::Provider['#{name}']"
<<
-
"Aeolus::Conductor::Provider::Account['#{name}']"
-
-
+ account_name = ask("Rackspace Username: ")
+ account_password = ask("Rackspace API Key: "){ |q| q.echo = false }
+
elsif type == :ec2
- endpoint = ask("EC2 Endpoint: ")
- access_key = ask("EC2 Access Key: ")
- secret_access_key = ask("EC2 Secret Access Key: "){ |q| q.echo =
false }
- account_id = ask("EC2 Account ID: ")
- public_cert = ask("EC2 Public Cert: ")
- private_key = ask("EC2 Private Key: ")
- profile += "aeolus::provider{#{name}:\n" +
- " type => 'ec2',\n" +
- " endpoint => '#{endpoint}',\n" +
- " port => '#{provider_port += 1}',\n" +
- " require => Aeolus::Conductor::Login['admin']
}\n\n" +
- "aeolus::conductor::provider::account{#{name}:\n" +
- " provider => '#{name}',\n" +
- " type => 'ec2',\n" +
- " username => '#{access_key}',\n" +
- " password => '#{secret_access_key}',\n" +
- " account_id => '#{account_id}',\n" +
- " x509private => '#{private_key}',\n" +
- " x509public => '#{public_cert}',\n" +
- " require => Aeolus::Provider['#{name}']
}\n\n"
- profile_requires << "Aeolus::Provider['#{name}']"
<<
-
"Aeolus::Conductor::Provider::Account['#{name}']"
-
+ provider[:deltacloud_provider] = ask("EC2 Endpoint: ")
+ account[:account_id] = ask("EC2 Account ID: ")
+ account_name = ask("EC2 Access Key: ")
+ account_password = ask("EC2 Secret Access Key (hidden):
"){ |q| q.echo = false }
+ account[:x509public] = ask("EC2 Public Cert: ")
+ account[:x509private] = ask("EC2 Private Key: ")
+
end
+
+ profile += aeolus_provider :provider_name => name,
+ :provider_driver => type,
+ :account_username => account_name,
+ :account_password => account_password,
+ :provider => provider,
+ :account => account
+ profile_requires += ', ' unless profile_requires == ''
+ profile_requires +=
"Aeolus::Conductor::Provider::Account['#{account_name}']"
+ AeolusConfig.providers << [name,type,account_name,account_password]
end
end
# create the profile
text = File.read PROFILE_RECIPE
File.open(PROFILE_RECIPE, 'w+'){|f|
- requires = profile_requires.join(',')
- requires += ", " unless requires == ""
- f << text.gsub(/#AEOLUS_SEED_DATA_REQUIRES/, requires).
+ f << text.gsub(/#AEOLUS_SEED_DATA_REQUIRES/, profile_requires).
gsub(/#AEOLUS_SEED_DATA/, profile)
}
@@ -144,21 +174,22 @@ def interactive_installer
end
def interactive_deployer
- NODE_YAML='/etc/aeolus-configure/nodes/deploy'
-
PROFILE_RECIPE='/usr/share/aeolus-configure/modules/aeolus/manifests/profiles/deploy.pp'
+ NODE_YAML='/etc/aeolus-configure/nodes/post'
+
PROFILE_RECIPE='/usr/share/aeolus-configure/modules/aeolus/manifests/profiles/post.pp'
IMAGE_TEMPLATE='/etc/aeolus-configure/custom_template.tdl'
+ profile, profiles_requires = '', ''
+ packages, repos = '', ''
+
while clear_screen && agree("Deploy an instance to providers (y/n)?
")
name = ask("Instance name: ")
AeolusConfig.providers.each { |provider|
- pname,ptype = *provider
- profile += "aeolus::image{#{pname}-#{name}:\n" +
- " target => '#{ptype}',\n" +
- " template => 'custom_template.tdl',\n" +
- " provider => '#{pname}',\n" +
- " hwp => '#{ptype == :rackspace ? 'hwp2' :
'hwp1' }',\n" +
- " require =>
[Aeolus::Conductor::Provider::Account['#{pname}'],
Aeolus::Conductor::Hwp['hwp1', 'hwp2']] }\n\n"
- profile_requires << "Aeolus::Image['#{pname}-#{name}']"
+ provider_name,provider_type,username,password = *provider
+ profile += aeolus_image :name => name,
+ :provider => pname,
+ :provider_type => ptype
+ profile_requires += ', ' unless profile_requires == ''
+ profile_requires += "Aeolus::Image['#{provider_name}-#{name}']"
}
while agree("Add package repo to instance (y/n)? ")
@@ -174,18 +205,16 @@ def interactive_deployer
profile_packages += "<package name='#{package_name}' />"
end
- while agree("Add file? ") do
- src_location = ask("File Source: ")
- dst_location = ask("File Destination: ")
- end
+ #while agree("Add file (y/n)? ") do # TODO
+ # src_location = ask("File Source: ")
+ # dst_location = ask("File Destination: ")
+ #end
end
# create the profile
text = File.read PROFILE_RECIPE
File.open(PROFILE_RECIPE, 'w+'){|f|
- requires = profile_requires.join(',')
- requires += ", " unless requires == ""
- f << text.gsub(/#AEOLUS_SEED_DATA_REQUIRES/, requires).
+ f << text.gsub(/#AEOLUS_SEED_DATA_REQUIRES/, profile_requires).
gsub(/#AEOLUS_SEED_DATA/, profile)
}
@@ -198,24 +227,55 @@ def interactive_deployer
end
def interactive_migrator
- NODE_YAML='/etc/aeolus-configure/nodes/migrate'
-
PROFILE_RECIPE='/usr/share/aeolus-configure/modules/aeolus/manifests/profiles/migrate.pp'
+ NODE_YAML='/etc/aeolus-configure/nodes/post'
+
PROFILE_RECIPE='/usr/share/aeolus-configure/modules/aeolus/manifests/profiles/post.pp'
+
+ profile, profiles_requires = '', ''
- # FIXME query providers for instances
+ # query providers for instances
+ require 'deltacloud'
+ api_url = 'http://localhost:3002/api'
+ instances =
+ AeolusConfig.providers.collect { |p|
+ client = DeltaCloud.new( p[2], p[3], api_url )
+ client.instances
+ }.flatten
while clear_screen && agree("Migrate instance between providers (y/n)?
")
- instance =
+ source_instance =
choose do |menu|
menu.prompt = "Migrate Instance: "
- instances.each { |i| menu.choice i }
+ instances.each { |i| menu.choice i.name }
end
+ source_instance = instances.find { |i| i.name == source_instance }
+ source_instance_name = source_instance.split('-').last
+
+ source_instance_key = ask("Root ssh key location for instance: ")
dest_provider =
choose do |menu|
menu.prompt = "To Provider: "
AeolusConfig.providers.each { |p| menu.choice p[0] }
end
+
+ dest_instance_key = ask("Root ssh key location for new instance: ")
+
+ provider = AeolusConfig.providers.find { |p| p[0] == dest_provider }
+ profile += aeolus_instance_snapshot :ssh_key => source_instance_key,
+ :ip_address =>
source_instance.public_ip_addresses.first
+ profile += aeolus_terminate_instance :name =>
"#{source_instance.name}"
+
+ profile += aeolus_image :name =>
"#{provider[0]}-#{source_instance_name}",
+ :provider => provider[0],
+ :provider_type => provider[1]
+ profile += aeolus_instance_restore :ssh_key => dest_instance_key,
+ :ip_address => 'FIXME!?!?'
+
+
+ profile_requires += ', ' unless profile_requires == ''
+ profile_requires +=
"Aeolus::Image['#{provider_name}-#{source_instance_name}'],"
+ profile_requires +=
"Aeolus::Instance::Terminate['#{source_instance.name}']"
end
# create the profile
diff --git a/recipes/aeolus/manifests/conductor.pp
b/recipes/aeolus/manifests/conductor.pp
index ad7fb24..2d5c3e2 100644
--- a/recipes/aeolus/manifests/conductor.pp
+++ b/recipes/aeolus/manifests/conductor.pp
@@ -274,3 +274,13 @@ define aeolus::conductor::hwp($memory='', $cpu='',
$storage='', $architecture=''
require => [Service['aeolus-conductor'],
Exec['grant_site_admin_privs']]
}
}
+
+define aeolus::instance::terminate(){
+ web_request{ "delete-$name":
+ post =>
"https://localhost/conductor/deployments/delete?instance=$name",
+ returns => 200,
+ follow => true,
+ use_cookies_at => '/tmp/aeolus-admin',
+ require => [Service['aeolus-conductor'],
Exec['grant_site_admin_privs']]
+ }
+}
diff --git a/recipes/aeolus/manifests/init.pp b/recipes/aeolus/manifests/init.pp
index 871f86f..09d1537 100644
--- a/recipes/aeolus/manifests/init.pp
+++ b/recipes/aeolus/manifests/init.pp
@@ -5,6 +5,7 @@ import "apache"
import "rails"
import "selinux"
import "ntp"
+import "snap"
import "conductor"
import "deltacloud"
diff --git a/recipes/aeolus/manifests/profiles/deploy.pp
b/recipes/aeolus/manifests/profiles/deploy.pp
deleted file mode 100644
index ecd481a..0000000
--- a/recipes/aeolus/manifests/profiles/deploy.pp
+++ /dev/null
@@ -1,10 +0,0 @@
-class aeolus::profiles::deploy {
-
-aeolus::conductor::login{"admin": password => "password",
- require => Aeolus::Conductor::Site_admin['admin']}
-
-#AEOLUS_SEED_DATA
-
-aeolus::conductor::logout{"admin":
- require => [#AEOLUS_SEED_DATA_REQUIRES]}
-}
diff --git a/recipes/aeolus/manifests/profiles/migrate.pp
b/recipes/aeolus/manifests/profiles/migrate.pp
deleted file mode 100644
index 87f6673..0000000
--- a/recipes/aeolus/manifests/profiles/migrate.pp
+++ /dev/null
@@ -1,9 +0,0 @@
-class aeolus::profiles::migrate {
-aeolus::conductor::login{"admin": password => "password",
- require => Aeolus::Conductor::Site_admin['admin']}
-
-#AEOLUS_SEED_DATA
-
-aeolus::conductor::logout{"admin":
- require => [#AEOLUS_SEED_DATA_REQUIRES]}
-}
diff --git a/recipes/aeolus/manifests/profiles/post.pp
b/recipes/aeolus/manifests/profiles/post.pp
new file mode 100644
index 0000000..9bc4c9b
--- /dev/null
+++ b/recipes/aeolus/manifests/profiles/post.pp
@@ -0,0 +1,10 @@
+class aeolus::profiles::migrate {
+aeolus::conductor::login{"admin": password => "password",
+ require => Aeolus::Conductor::Site_admin['admin']}
+
+#AEOLUS_SEED_DATA
+
+aeolus::conductor::logout{"admin":
+ require => [#AEOLUS_SEED_DATA_REQUIRES
+ ]}
+}
diff --git a/recipes/snap/manifests/init.pp b/recipes/snap/manifests/init.pp
new file mode 100644
index 0000000..a76d1ad
--- /dev/null
+++ b/recipes/snap/manifests/init.pp
@@ -0,0 +1,14 @@
+define snap::snapshot($ssh_key, $destination){
+ exec{"$name-snapshot":
+ command => "/usr/bin/ssh root@$name -i $ssh_key -c 'snaptool --backup
--files -f /tmp/$name-snapshot.tgz'" }
+ exec{"$name-snapshot-transfer":
+ command => "/usr/bin/scp -i $ssh_key root@$name:/tmp/$name-snapshot.tgz
$destination",
+ require => Exec["$name-snapshot"] }
+}
+
+define snap::restore($ssh_key, $source){
+ exec{"$name-snapshot-transfer":
+ command => "/usr/bin/scp -i $ssh_key $source
root@name:/tmp/$name-snapshot.tgz" }
+ exec{"$name-snapshot":
+ command => "/usr/bin/ssh root@$name -i $ssh_key -c 'snaptool --restore
--files -f /tmp/$name-snapshot.tgz'" }
+}
--
1.7.6