4 # Copyright 2016 RIFT.IO Inc
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
24 from gi
import require_version
25 require_version('RwCal', '1.0')
27 from gi
.repository
import RwcalYang
28 from gi
.repository
.RwTypes
import RwStatus
35 persistent_resources
= {
40 MISSION_CONTROL_NAME
= 'mission-control'
41 LAUNCHPAD_NAME
= 'launchpad'
43 RIFT_IMAGE_AMI
= 'ami-7070231a'
45 logging
.basicConfig(level
=logging
.ERROR
)
46 logger
= logging
.getLogger('rift.cal.awsresources')
47 logger
.setLevel(logging
.INFO
)
53 plugin
= rw_peas
.PeasPlugin('rwcal_aws', 'RwCal-1.0')
54 engine
, info
, extension
= plugin()
55 cal
= plugin
.get_interface("Cloud")
56 rwloggerctx
= rwlogger
.RwLog
.Ctx
.new("Cal-Log")
58 rc
= cal
.init(rwloggerctx
)
59 assert rc
== RwStatus
.SUCCESS
60 except Exception as e
:
61 logger
.error("ERROR:Cal plugin instantiation failed with exception %s",repr(e
))
63 logger
.info("AWS Cal plugin successfully instantiated")
66 def get_cal_account(**kwargs
):
68 Returns AWS cal account
70 account
= RwcalYang
.YangData_RwProject_Project_CloudAccounts_CloudAccountList()
71 account
.account_type
= "aws"
72 account
.aws
.key
= kwargs
['key']
73 account
.aws
.secret
= kwargs
['secret']
74 account
.aws
.region
= kwargs
['region']
75 if 'ssh_key' in kwargs
and kwargs
['ssh_key'] is not None:
76 account
.aws
.ssh_key
= kwargs
['ssh_key']
77 account
.aws
.availability_zone
= kwargs
['availability_zone']
78 if 'vpcid' in kwargs
and kwargs
['vpcid'] is not None:
79 account
.aws
.vpcid
= kwargs
['vpcid']
80 if 'default_subnet_id' in kwargs
and kwargs
['default_subnet_id'] is not None:
81 account
.aws
.default_subnet_id
= kwargs
['default_subnet_id']
84 class AWSResources(object):
86 Class with methods to manage AWS resources
88 def __init__(self
,**kwargs
):
89 self
._cal
= get_cal_plugin()
90 self
._acct
= get_cal_account(**kwargs
)
92 def _destroy_vms(self
):
96 logger
.info("Initiating VM cleanup")
97 rc
, rsp
= self
._cal
.get_vdu_list(self
._acct
)
98 vdu_list
= [vm
for vm
in rsp
.vdu_info_list
if vm
.name
not in persistent_resources
['vms']]
99 logger
.info("Deleting VMs : %s" %([x
.name
for x
in vdu_list
]))
102 self
._cal
.delete_vdu(self
._acct
, vdu
.vdu_id
)
104 logger
.info("VM cleanup complete")
106 def _destroy_networks(self
):
110 logger
.info("Initiating Network cleanup")
111 driver
= self
._cal
._get
_driver
(self
._acct
)
112 subnets
= driver
.get_subnet_list()
113 subnet_list
= [subnet
for subnet
in subnets
if subnet
.default_for_az
is False]
115 logger
.info("Deleting Networks : %s" %([x
.id for x
in subnet_list
]))
116 for subnet
in subnet_list
:
117 self
._cal
.delete_virtual_link(self
._acct
, subnet
.subnet_id
)
118 logger
.info("Network cleanup complete")
120 def destroy_resource(self
):
124 logger
.info("Cleaning up AWS resources")
126 self
._destroy
_networks
()
127 logger
.info("Cleaning up AWS resources.......[Done]")
129 def _destroy_mission_control(self
):
131 Destroy Mission Control VM
133 logger
.info("Initiating MC VM cleanup")
134 rc
, rsp
= self
._cal
.get_vdu_list(self
._acct
)
135 vdu_list
= [vm
for vm
in rsp
.vdu_info_list
if vm
.name
== MISSION_CONTROL_NAME
]
136 logger
.info("Deleting VMs : %s" %([x
.name
for x
in vdu_list
]))
139 self
._cal
.delete_vdu(self
._acct
, vdu
.vdu_id
)
140 logger
.info("MC VM cleanup complete")
142 def _destroy_launchpad(self
):
146 logger
.info("Initiating LP VM cleanup")
147 rc
, rsp
= self
._cal
.get_vdu_list(self
._acct
)
148 vdu_list
= [vm
for vm
in rsp
.vdu_info_list
if vm
.name
== LAUNCHPAD_NAME
]
149 logger
.info("Deleting VMs : %s" %([x
.name
for x
in vdu_list
]))
152 self
._cal
.delete_vdu(self
._acct
, vdu
.vdu_id
)
153 logger
.info("LP VM cleanup complete")
156 def create_mission_control(self
):
158 Create Mission Control VM in AWS
160 logger
.info("Creating mission control VM")
161 vdu
= RwcalYang
.YangData_RwProject_Project_VduInitParams()
162 vdu
.name
= MISSION_CONTROL_NAME
163 vdu
.image_id
= RIFT_IMAGE_AMI
164 vdu
.flavor_id
= 'c3.large'
165 vdu
.allocate_public_address
= True
166 vdu
.vdu_init
.userdata
= "#cloud-config\n\nruncmd:\n - echo Sleeping for 5 seconds and attempting to start salt-master\n - sleep 5\n - /bin/systemctl restart salt-master.service\n"
168 rc
,rs
=self
._cal
.create_vdu(self
._acct
,vdu
)
169 assert rc
== RwStatus
.SUCCESS
172 driver
= self
._cal
._get
_driver
(self
._acct
)
173 inst
=driver
.get_instance(self
._mc
_id
)
174 inst
.wait_until_running()
176 rc
,rs
=self
._cal
.get_vdu(self
._acct
,self
._mc
_id
, "")
177 assert rc
== RwStatus
.SUCCESS
178 self
._mc
_public
_ip
= rs
.public_ip
179 self
._mc
_private
_ip
= rs
.management_ip
181 logger
.info("Started Mission Control VM with id %s and IP Address %s\n",self
._mc
_id
, self
._mc
_public
_ip
)
183 def create_launchpad_vm(self
, salt_master
= None):
185 Create Launchpad VM in AWS
187 salt_master (String): String with Salt master IP typically MC VM private IP
189 logger
.info("Creating launchpad VM")
190 USERDATA_FILENAME
= os
.path
.join(os
.environ
['RIFT_INSTALL'],
191 'etc/userdata-template')
194 fd
= open(USERDATA_FILENAME
, 'r')
195 except Exception as e
:
198 LP_USERDATA_FILE
= fd
.read()
199 # Run the enable lab script when the openstack vm comes up
200 LP_USERDATA_FILE
+= "runcmd:\n"
201 LP_USERDATA_FILE
+= " - echo Sleeping for 5 seconds and attempting to start elastic-network-interface\n"
202 LP_USERDATA_FILE
+= " - sleep 5\n"
203 LP_USERDATA_FILE
+= " - /bin/systemctl restart elastic-network-interfaces.service\n"
205 if salt_master
is None:
206 salt_master
=self
._mc
_private
_ip
207 node_id
= str(uuid
.uuid4())
209 vdu
= RwcalYang
.YangData_RwProject_Project_VduInitParams()
210 vdu
.name
= LAUNCHPAD_NAME
211 vdu
.image_id
= RIFT_IMAGE_AMI
212 vdu
.flavor_id
= 'c3.xlarge'
213 vdu
.allocate_public_address
= True
214 vdu
.vdu_init
.userdata
= LP_USERDATA_FILE
.format(master_ip
= salt_master
,
216 vdu
.node_id
= node_id
218 rc
,rs
=self
._cal
.create_vdu(self
._acct
,vdu
)
219 assert rc
== RwStatus
.SUCCESS
222 driver
= self
._cal
._get
_driver
(self
._acct
)
223 inst
=driver
.get_instance(self
._lp
_id
)
224 inst
.wait_until_running()
226 rc
,rs
=self
._cal
.get_vdu(self
._acct
,self
._lp
_id
, "")
227 assert rc
== RwStatus
.SUCCESS
229 self
._lp
_public
_ip
= rs
.public_ip
230 self
._lp
_private
_ip
= rs
.management_ip
231 logger
.info("Started Launchpad VM with id %s and IP Address %s\n",self
._lp
_id
, self
._lp
_public
_ip
)
233 def upload_ssh_key_to_ec2(self
):
235 Upload SSH key to EC2 region
237 driver
= self
._cal
._get
_driver
(self
._acct
)
238 key_name
= os
.getlogin() + '-' + 'sshkey'
239 key_path
= '%s/.ssh/id_rsa.pub' % (os
.environ
['HOME'])
240 if os
.path
.isfile(key_path
):
241 logger
.info("Uploading ssh public key file in path %s with keypair name %s", key_path
,key_name
)
242 with
open(key_path
) as fp
:
243 driver
.upload_ssh_key(key_name
,fp
.read())
245 logger
.error("Valid Public key file %s not found", key_path
)
252 parser
= argparse
.ArgumentParser(description
='Script to manage AWS resources')
254 parser
.add_argument('--aws-key',
260 parser
.add_argument('--aws-secret',
266 parser
.add_argument('--aws-region',
272 parser
.add_argument('--aws-az',
276 help='AWS Availability zone')
278 parser
.add_argument('--aws-sshkey',
282 help='AWS SSH Key to login to instance')
284 parser
.add_argument('--aws-vpcid',
288 help='AWS VPC ID to use to indicate non default VPC')
290 parser
.add_argument('--aws-default-subnet',
292 dest
= 'aws_default_subnet',
294 help='AWS Default subnet id in VPC to be used for mgmt network')
296 parser
.add_argument('--mission-control',
297 action
= 'store_true',
298 dest
= 'mission_control',
299 help='Create Mission Control VM')
301 parser
.add_argument('--launchpad',
302 action
= 'store_true',
304 help='Create LaunchPad VM')
306 parser
.add_argument('--salt-master',
308 dest
= 'salt_master',
310 help='IP Address of salt controller. Required, if only launchpad VM is being created.')
312 parser
.add_argument('--cleanup',
317 help = 'Perform resource cleanup for AWS installation. \n Possible options are {all, mc, lp, vms, networks }')
319 parser
.add_argument('--upload-ssh-key',
320 action
= 'store_true',
321 dest
= 'upload_ssh_key',
322 help = 'Upload users SSH public key ~/.ssh/id_rsa.pub')
324 argument
= parser
.parse_args()
326 if (argument
.aws_key
is None or argument
.aws_secret
is None or argument
.aws_region
is None or
327 argument
.aws_az
is None):
328 logger
.error("Missing mandatory params. AWS Key, Secret, Region, AZ and SSH key are mandatory params")
331 if (argument
.cleanup
is None and argument
.mission_control
is None and argument
.launchpad
is None
332 and argument
.upload_ssh_key
is None):
333 logger
.error('Insufficient parameters')
337 logger
.info("Instantiating cloud-abstraction-layer")
338 drv
= AWSResources(key
=argument
.aws_key
, secret
=argument
.aws_secret
, region
=argument
.aws_region
, availability_zone
= argument
.aws_az
,
339 ssh_key
= argument
.aws_sshkey
, vpcid
= argument
.aws_vpcid
, default_subnet_id
= argument
.aws_default_subnet
)
340 logger
.info("Instantiating cloud-abstraction-layer.......[Done]")
342 if argument
.upload_ssh_key
:
343 drv
.upload_ssh_key_to_ec2()
345 if argument
.cleanup
is not None:
346 for r_type
in argument
.cleanup
:
348 drv
.destroy_resource()
352 if r_type
== 'networks':
353 drv
._destroy
_networks
()
355 drv
._destroy
_mission
_control
()
357 drv
._destroy
_launchpad
()
359 if argument
.mission_control
== True:
360 drv
.create_mission_control()
362 if argument
.launchpad
== True:
363 if argument
.salt_master
is None and argument
.mission_control
is False:
364 logger
.error('Salt Master IP address not provided to start Launchpad.')
367 drv
.create_launchpad_vm(argument
.salt_master
)
369 if __name__
== '__main__':