add code to upload to amazon aws using ec2-api-tools and ec2-ami-tools:
authorPaul Tonelli <paul.tonelli@logilab.fr>
Fri, 19 Apr 2013 19:37:36 +0200
changeset 118 819d80ebd10e
parent 117 a722452444fc
child 119 d99899db3edd
add code to upload to amazon aws using ec2-api-tools and ec2-ami-tools: - ami_post/init.sls: moved upload code to ami_post/upload.sls - ami_post/upload.sls: added code for amazon aws: - create certificate and private key file - use upload function from aws_client module - _module/aws_client.py: functions to upload to amazon - readme: add information about options necessary to upload to amazon.
_modules/aws_client.py
ami_post/init.sls
ami_post/upload.sls
readme.rst
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/_modules/aws_client.py	Fri Apr 19 19:37:36 2013 +0200
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+'''
+this module replaces temporarely the glance script from salt
+(unavailable due to glanceclient not being available in debian)
+
+it also relies on the nova script (which works)
+'''
+
+from time import sleep
+import os
+import logging
+
+log = logging.getLogger(__name__)
+
+# Import third party libs
+def create_ec2_volume(size, availability_zone, region, cert_path, pk_path):
+    ec2_create_output = __salt__['cmd.run']("ec2-create-volume --size 1 --availability-zone " + availability_zone + " --region " + region +  " -K " + pk_path + " -C " + cert_path)
+    for bloc in ec2_create_output.split('\t'):
+        if bloc.find('vol-') != -1:
+            volume_id = bloc
+            return volume_id
+    return None
+
+def create_snapshot(volume_id, ami_name, region, cert_path, pk_path):
+    ec2_snapshot_output = __salt__['cmd.run']("ec2-create-snapshot --region " + region + " -K " +
+            pk_path + " -C " + cert_path + " -d " + ami_name + " " + volume_id)
+    for bloc in ec2_snapshot_output.split('\t'):
+        if bloc.find('snap-') != -1:
+            snapshot_id = bloc
+            return snapshot_id
+    return None
+
+def snapshot_complete(snapshot_id, region, cert_path, pk_path):
+    ec2_snapshot_status = __salt__['cmd.run']("ec2-describe-snapshots " +
+            snapshot_id  + " --region " + region + " -K " +
+            pk_path + " -C " + cert_path)
+    for bloc in ec2_snapshot_status.split('\t'):
+        if bloc.find('completed') == 0:
+            log.info('snapshot ready')
+            return True
+    log.info('snapshot not ready')
+    return False
+
+def upload(filename,
+        ami_name,
+        region="eu-west-1",
+        cert_path="/tmp/certificate.pem",
+        pk_path="/tmp/private-key.pem",
+        size=1):
+    '''
+    upload .img file to amazon aws using the ec2 interface
+    performs the following steps:
+        - create and attach volume
+        - dd file to volume
+        - detach volume
+        - create snapshot
+        - wait for snapshot to be completed
+        - register image using snapshot and specified aki
+        - delete volume
+    '''
+    availability_zone = __salt__['cmd.run']("ec2metadata|grep availability-zone|awk '{print $2}'")
+    instance_id = __salt__['cmd.run']("ec2metadata|grep instance-id|awk '{print $2}'")
+    volume_id = create_ec2_volume(size, availability_zone, region, cert_path, pk_path)
+    log.info(__salt__['cmd.run']("ec2-attach-volume " + volume_id + " --instance " +
+            instance_id + " --device /dev/sdf --region " + region + " -K " +
+            pk_path + " -C " + cert_path))
+    while not os.path.exists('/dev/xvdf'):
+        sleep(1)
+    log.info(__salt__['cmd.run']("dd bs=64M if=" + filename +  " of=/dev/xvdf"))
+    log.info(__salt__['cmd.run']("ec2-detach-volume " + volume_id + " --instance " +
+            instance_id + " --device /dev/sdf --region " + region + " -K " +
+            pk_path + " -C " + cert_path + " --force"))
+    snapshot_id = create_snapshot(volume_id, ami_name, region, cert_path, pk_path)
+    while not snapshot_complete(snapshot_id, region, cert_path, pk_path):
+        sleep(10)
+    log.info(__salt__['cmd.run']("ec2-register -n " + ami_name + " -a x86_64  -s " +
+            snapshot_id + " --kernel aki-71665e05  --region " + region + " -K "
+            + pk_path + " -C " + cert_path))
+    log.info(__salt__['cmd.run']("ec2-delete-volume --region " + region + " -K " +
+        pk_path + " -C " + cert_path + " " + volume_id ))
--- a/ami_post/init.sls	Thu Apr 18 19:08:51 2013 +0200
+++ b/ami_post/init.sls	Fri Apr 19 19:37:36 2013 +0200
@@ -85,13 +85,7 @@
         - require:
             - tmp_state.unmounted: umount_chroot_slash
 
-{% if 'keystone.user' in grains %}
-upload_variant:
-    module.run:
-        - name: vm_create.upload_to_glance
-        - path: /mnt/output
-    require:
-        - tmp_state.resized: resize_variation
-{% endif %}
+include:
+    - ami_post.upload
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ami_post/upload.sls	Fri Apr 19 19:37:36 2013 +0200
@@ -0,0 +1,67 @@
+{% if 'keystone.user' in grains %}
+upload_variant:
+    module.run:
+        - name: vm_create.upload_to_glance
+        - path: /mnt/output
+        - require:
+            - tmp_state.resized: resize_variation
+{% endif %}
+
+{% if 'aws.private_key' in grains and'aws.certificate' in grains %}
+/tmp/certificate.pem.long:
+    file.append:
+        - text: 
+            - -----BEGIN CERTIFICATE-----
+            - {{ grains['aws.certificate'] }}
+            - -----END CERTIFICATE-----
+        - makedirs: True
+        - require:
+            - tmp_state.resized: resize_variation
+
+space_remove_cert:
+    cmd:
+        - run
+        - name: cat /tmp/certificate.pem.long|sed 's/ //g' > /tmp/certificate.pem
+        - require:
+            - file.append: /tmp/certificate.pem.long
+
+/tmp/private-key.pem.long:
+    file.append:
+        - text: 
+            - -----BEGIN RSA PRIVATE KEY-----
+            - {{ grains['aws.private_key'] }}
+            - -----END RSA PRIVATE KEY-----
+        - makedirs: True
+        - require:
+            - tmp_state.resized: resize_variation
+
+space_remove_pk:
+    cmd:
+        - run
+        - name: cat /tmp/private-key.pem.long|sed 's/ //g' > /tmp/private-key.pem
+        - require:
+            - file.append: /tmp/private-key.pem.long
+
+aws_client.upload:
+    module.run:
+        - filename: /mnt/output/variation.img 
+{% if 'ami.name' in grains %}
+        - ami_name: {{ grains['ami.name'] }} 
+{% else %}
+        - ami_name: new_variation
+{% endif %}
+{% if 'aws.region' in grains %}
+        - region: {{ grains['aws.region'] }}
+{% else %}
+        - region: eu-west-1
+{% endif %}
+        - cert_path: /tmp/certificate.pem
+        - pk_path: /tmp/private-key.pem
+{% if 'ami.size' in grains %}
+        - size: {{grains['ami.size']}}
+{% endif %}
+        - require:
+            - tmp_state.resized: resize_variation
+            - cmd.run: space_remove_pk
+            - cmd.run: space_remove_cert
+{% endif %}
--- a/readme.rst	Thu Apr 18 19:08:51 2013 +0200
+++ b/readme.rst	Fri Apr 19 19:37:36 2013 +0200
@@ -77,15 +77,30 @@
      keystone.auth_url: 'http://control.example.com:5000/v2.0'
      keystone.insecure: False   #(optional)
 
+     ### optionnal (necessary to upload to amazon aws) ###
+     ### remove the BEGIN and END statements found in the files ###
+     ### do not forget the ' ' at each newline for ConfigParser ###
+     aws.region: eu-west-1
+     aws.private_key: 0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+     aws.certificate: 0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+
      ====== END ========
 
 3. you can then connect to your instance and wait until everything in ``/mnt``
-   is unmounted. Upload to glance (openstack) is automatic if you provided the
-   correct user data. If you want to upload to amazon ec2, you need to follow
-   the following steps: 
-
-.. sourcecode:: bash
-     root@amibuilder:~#  
+   is unmounted. Upload to glance (openstack) or amazon aws is automatic if you
+   provided the correct user data. 
 
 Main Files
 ----------