Skip to content
This repository has been archived by the owner on Jul 18, 2023. It is now read-only.

Commit

Permalink
Merge pull request #48 from BlackSmith/master
Browse files Browse the repository at this point in the history
The better detection of end of the installation. The option and non-option arguments can be intermixed (GNU style scanning mode)
  • Loading branch information
BlackSmith authored Jun 19, 2018
2 parents b0913fa + db091ad commit 891442b
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 43 deletions.
10 changes: 7 additions & 3 deletions 5minute.spec
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
Name: 5minute
Version: 0.2.30
Version: 0.2.31

Release: 1%{?dist}
Release: 0%{?dist}
Summary: Command line tool for getting instance from OpenStack

License: GPLv2
URL: https://github.com/SatelliteQE/5minute
Source0: https://github.com/BlackSmith/%{name}/archive/%{version}.tar.gz
Source0: https://github.com/SatelliteQE/%{name}/archive/%{name}-%{version}.tar.gz

BuildArch: noarch
BuildRequires: python3-devel
Expand Down Expand Up @@ -52,3 +52,7 @@ Give me an instance of mine image on OpenStack. Hurry!
%{python3_sitelib}/*

%changelog
* Tue Jun 19 2018 Martin Korbel <[email protected]> - 0.2.31-0
- The better detection of end of the installation
- The option and non-option arguments can be intermixed (GNU style scanning mode)
- Update cinderclient to API v2
87 changes: 47 additions & 40 deletions vminute/vminute.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
from neutronclient.neutron import client as neutron_client
from novaclient import client as nova_client
from novaclient import exceptions as nova_exceptions
from keystoneauth1.identity import v3 as keystoneIdentity
from keystoneauth1 import loading as keystoneLoading
from keystoneauth1 import session as keystoneSession
from keystoneclient.v3 import client as keystone_client
Expand Down Expand Up @@ -212,7 +211,6 @@ class BaseClass(object):
__keystone = None
__cinder = None
__heat = None
__token = None
__session = None
__neutron = None
__first_check = False
Expand Down Expand Up @@ -271,7 +269,7 @@ def _check_key(self):

def __get_cinder(self):
if not self.__cinder:
self.__cinder = cinder_client.Client(1, session=self.__get_session())
self.__cinder = cinder_client.Client(2, session=self.__get_session())
return self.__cinder

def __get_heat(self):
Expand Down Expand Up @@ -311,11 +309,6 @@ def __get_nova(self):
self.__nova = nova_client.Client(2, session=self.__get_session())
return self.__nova

def __get_token(self):
if not self.__token:
self.__token = auth.get_token(self.__get_session())
return self.__token

def __get_session(self):
if not self.__session:
self.__checkenv()
Expand Down Expand Up @@ -347,8 +340,6 @@ def __getattr__(self, name):
return self.__get_nova()
elif name == 'keystone':
return self.__get_keystone()
elif name == 'token':
return self.__get_token()
elif name == 'neutron':
return self.__get_neutron()
elif name == 'glance':
Expand Down Expand Up @@ -543,14 +534,14 @@ def get_image(self, id):
@catch_exception("Name of the volume is ambiguous, please use ID.", cinder_exceptions.NoUniqueMatch)
def get_volume(self, id):
if re.match(r'^[0-9a-f\-]+$', id) is None:
return self.cinder.volumes.find(display_name=id)
return self.cinder.volumes.find(name=id)
else:
return self.cinder.volumes.get(id)

@catch_exception("The snapshot doesn't exist.")
def get_snapshot(self, id):
if re.match(r'^[0-9a-f\-]+$', id) is None:
return self.cinder.volume_snapshots.find(display_name=id)
return self.cinder.volume_snapshots.find(name=id)
else:
return self.cinder.volume_snapshots.get(id)

Expand Down Expand Up @@ -592,7 +583,6 @@ def get_count_free_ip(cidr, flist):

nets = self.get_networks(filter={'name': "^default-", "router:external": False})
max_network_space = 0
current_biggest_network = None
flist = self.neutron.list_floatingips().get('floatingips')
res = list()
for net in nets:
Expand Down Expand Up @@ -696,7 +686,7 @@ def __parse_params(self, opts, argv):
@catch_exception("Bad parameter. Please try 5minute kill help.")
def cmd(self, argv):
opts, argv = \
getopt.getopt(argv, "hs", ['help', 'skip-volume'])
getopt.gnu_getopt(argv, "hs", ['help', 'skip-volume'])
if 'help' not in argv:
self.params = self.__parse_params(opts, argv)
if 'help' in argv or 'help' in self.params:
Expand Down Expand Up @@ -828,9 +818,9 @@ def __parse_params(self, opts, argv):
@catch_exception("Bad parameter. Please try 5minute snapshot help.")
def cmd(self, argv):
opts, argv = \
getopt.getopt(argv, "husn:m:",
['help', 'volume', 'umount', 'name=', 'metadata=',
'shutdown', 'delete'])
getopt.gnu_getopt(argv, "husn:m:",
['help', 'volume', 'umount', 'name=', 'metadata=',
'shutdown', 'delete'])
if 'help' not in argv:
self.params = self.__parse_params(opts, argv)
if 'help' in argv or 'help' in self.params:
Expand Down Expand Up @@ -971,6 +961,10 @@ class BootInstanceClass(ServerClass):
created_volume = False
cinit_ending_text = "===============_CLOUD_INIT_FINISHED_==============="

output_cache = []
output_compare_lines = 5
output_len = 0

def __parse_params(self, opts, argv):
params = {}
for key, val in opts:
Expand Down Expand Up @@ -1007,9 +1001,9 @@ def __parse_params(self, opts, argv):
@catch_exception("Bad parameter. Please try 5minute boot --help.")
def cmd(self, argv):
opts, argv = \
getopt.getopt(argv, "hcf:n:v:p:",
['help', 'console', 'flavor=', 'name=', 'volume=',
'userdata=', 'novolume', 'noip'])
getopt.gnu_getopt(argv, "hcf:n:v:p:",
['help', 'console', 'flavor=', 'name=', 'volume=',
'userdata=', 'novolume', 'noip'])
self.params = self.__parse_params(opts, argv)
if 'help' in self.params:
self.help()
Expand Down Expand Up @@ -1107,7 +1101,6 @@ def __setup_networking(self):

@catch_exception("The problem with downloading of the userdata script for this image")
def __setup_userdata_script(self, image):
res = None
filenames = None
if "userdata" in self.params:
filenames = self.params['userdata']
Expand All @@ -1121,7 +1114,7 @@ def __setup_userdata_script(self, image):
cscript = re.sub(r'^#!/bin/bash', '', cscript, flags=re.M)
self.params['cscript'] += cscript.format(**self.variables)
self.params['cscript'] += "\n"
self.params['cscript'] += 'echo "\n%s" > /dev/ttyS0;' %\
self.params['cscript'] += 'echo "\n%s\n\n" > /dev/ttyS0;' %\
self.cinit_ending_text
self.params['cscript'] += 'wall "%s"' % self.cinit_ending_text
progress(result="DONE")
Expand All @@ -1135,7 +1128,7 @@ def __setup_volume(self, image):
# Is the volume_name name/id of existing volume?
try:
self.volume = self.get_volume(volume_name)
except cinder_exceptions.NotFound as ex:
except cinder_exceptions.NotFound:
pass
if self.volume is None:
# The volume_name is name of snapshot,
Expand All @@ -1150,7 +1143,7 @@ def __create_new_volume(self, volume_name, image):
snap = self.get_snapshot(volume_name)
name = self.variables.get('name')
vol = self.cinder.volumes.create(size=snap.size, snapshot_id=snap.id,
display_name=name)
name=name)
while vol.status == 'creating':
progress()
time.sleep(1)
Expand All @@ -1176,6 +1169,32 @@ def __choose_flavor(self, image):
.format(**self.variables['flavor'].__dict__)
progress(result=flavor)

def __getOutput(self, server, num_rows=None):
if len(self.output_cache) == 0:
num_rows = None
output = server.get_console_output(num_rows)
# cut off incomplete row
output = output[0:output.rfind("\n")].replace("\b", "").split("\n")
output = list(filter(None, output))
if len(self.output_cache) != 0:
com = 0
while len(output) > 0 and com < self.output_compare_lines\
and com < len(self.output_cache):
# We try to find end of previous output
line = output.pop(0)
if line == self.output_cache[com]:
com += 1
else:
com = 0
if com < self.output_compare_lines and com < len(self.output_cache)\
and num_rows is not None and num_rows < 200:
# If we can not find end of previous output, we try check
# twice bigger set
return self.__getOutput(server, num_rows * 2)
# save the latest few rows for next checking
self.output_cache = output[-1*self.output_compare_lines:]
return output

def __create_instance(self, image):
progress(title="Instance name:", result=self.variables.get('name'))
progress("Creating a new instance:")
Expand Down Expand Up @@ -1209,7 +1228,6 @@ def __create_instance(self, image):
self.__check_console_output(server)

def __check_console_output(self, server):
lindex = 0
show_output = self.params.get('console')
exit_status = None
exit_message = "DONE"
Expand All @@ -1222,25 +1240,15 @@ def __check_console_output(self, server):
print("Booting of the instance:")
else:
progress(title="Booting of the instance:")
output = server.get_console_output()
# cut off incomplete row
# output = output[0:output.rfind("\n")]
length_old = 0
while counter > 0 and exit_status is None:
length = len(output)
if length_old > length:
# WA: sometime old_length is bigger then current length
length_old = length - 1000
if length == length_old:
output = "\n".join(self.__getOutput(server, 10))
if len(output) == 0:
counter -= 1
time.sleep(1)
if not show_output:
progress()
else:
counter = 300
# we can work only with new lines
output = output[-1 * (length - length_old):]
length_old = length
if re.search(r'(.*error.*)', output, flags=re.I & re.M):
exit_message = "Errors in the userdata script"
if show_output:
Expand All @@ -1254,14 +1262,13 @@ def __check_console_output(self, server):
r"\033[31;01m\1\033[39;49;00m",
output, flags=re.I & re.M)
sys.stdout.write("%s\n" % output)
sys.stdout.flush()
else:
progress()
if reg_exit.search(output):
counter = 0
if exit_status is None:
exit_status = True
break
output = server.get_console_output()
if not show_output:
progress(result=exit_message)
if exit_status is None:
Expand Down Expand Up @@ -1356,7 +1363,7 @@ class BootScenarioClass(ScenarioClass):
@catch_exception("Bad parameter. Please try 5minute scenario boot --help.")
def cmd(self, argv):
params = dict()
opts, argv2 = getopt.getopt(argv, "n:h", ['name=', 'help'])
opts, argv2 = getopt.gnu_getopt(argv, "n:h", ['name=', 'help'])
for key, val in opts:
if key in ('--help', '-h'):
self.help()
Expand Down

0 comments on commit 891442b

Please sign in to comment.