From 2c208062452b2e289a0b15630348538e1754dcca Mon Sep 17 00:00:00 2001 From: Dmitry Teselkin Date: Thu, 21 Mar 2013 17:26:49 +0400 Subject: [PATCH 01/14] Userdata script updated to support computer renaming functionality --- conductor/data/init.ps1 | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/conductor/data/init.ps1 b/conductor/data/init.ps1 index 620792c..12c2453 100644 --- a/conductor/data/init.ps1 +++ b/conductor/data/init.ps1 @@ -3,12 +3,34 @@ $WindowsAgentConfigBase64 = '%WINDOWS_AGENT_CONFIG_BASE64%' $WindowsAgentConfigFile = "C:\Keero\Agent\WindowsAgent.exe.config" +$NewComputerName = '%INTERNAL_HOSTNAME%' + +$RestartRequired = $false + Import-Module CoreFunctions -Stop-Service "Keero Agent" -Backup-File $WindowsAgentConfigFile -Remove-Item $WindowsAgentConfigFile -Force -ConvertFrom-Base64String -Base64String $WindowsAgentConfigBase64 -Path $WindowsAgentConfigFile -Exec sc.exe 'config','"Keero Agent"','start=','delayed-auto' -Start-Service 'Keero Agent' -Write-Log 'All done!' \ No newline at end of file +if ( $WindowsAgentConfigBase64 -ne '%WINDOWS_AGENT_CONFIG_BASE64%' ) { + Write-Log "Updating Keero Windows Agent." + Stop-Service "Keero Agent" + Backup-File $WindowsAgentConfigFile + Remove-Item $WindowsAgentConfigFile -Force + ConvertFrom-Base64String -Base64String $WindowsAgentConfigBase64 -Path $WindowsAgentConfigFile + Exec sc.exe 'config','"Keero Agent"','start=','delayed-auto' + Write-Log "Service has been updated." +} + +if ( $NewComputerName -ne '%INTERNAL_HOSTNAME%' ) { + Write-Log "Renaming computer ..." + Rename-Computer -NewName $NewComputerName | Out-Null + Write-Log "New name assigned, restart required." + $RestartRequired = $true +} + +Write-Log 'All done!' +if ( $RestartRequired ) { + Write-Log "Restarting computer ..." + Restart-Computer -Force +} +else { + Start-Service 'Keero Agent' +} From f202ac273b45b2aac06da3d9195a27c4ca11da44 Mon Sep 17 00:00:00 2001 From: Dmitry Teselkin Date: Thu, 21 Mar 2013 17:28:12 +0400 Subject: [PATCH 02/14] All Cloudbase-Init plugins disabled except UserDataPlugin --- Deployment/cloudbase-init/config/cloudbase-init.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/Deployment/cloudbase-init/config/cloudbase-init.conf b/Deployment/cloudbase-init/config/cloudbase-init.conf index 57d1faa..0b167a0 100644 --- a/Deployment/cloudbase-init/config/cloudbase-init.conf +++ b/Deployment/cloudbase-init/config/cloudbase-init.conf @@ -8,3 +8,4 @@ config_drive_cdrom=false verbose=true logdir=C:\Program Files (x86)\Cloudbase Solutions\Cloudbase-Init\log\ logfile=cloudbase-init.log +plugins=cloudbaseinit.plugins.windows.userdata.UserDataPlugin \ No newline at end of file From 9964cd217592f280d02753698d4856e2a51edff8 Mon Sep 17 00:00:00 2001 From: Timur Nurlygayanov Date: Thu, 21 Mar 2013 18:05:46 +0400 Subject: [PATCH 03/14] Added deployment script for automated tests. --- tests/deploy.sh | 49 ++++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 25 deletions(-) mode change 100644 => 100755 tests/deploy.sh diff --git a/tests/deploy.sh b/tests/deploy.sh old mode 100644 new mode 100755 index e57207d..cad10a2 --- a/tests/deploy.sh +++ b/tests/deploy.sh @@ -24,10 +24,20 @@ expect "*$*" send -- "./unstack.sh\n" expect "*$*" send -- "./stack.sh\n" -expect "*Would you like to start it now?*" +expect "*/usr/bin/service: 123: exec: status: not found*" send -- "y\n" expect "*stack.sh completed*" +send -- "sudo rabbitmq-plugins enable rabbitmq_management\n" +expect "*$*" +send -- "sudo service rabbitmq-server restart\n" +expect "*$*" +send -- "sudo rabbitmqctl add_user keero keero\n" +expect "*$*" +send -- "sudo rabbitmqctl set_user_tags keero administrator\n" +expect "*$*" + + send -- "source openrc admin admin\n" expect "*$*" @@ -37,7 +47,7 @@ expect "*$*" send -- "nova keypair-add keero-linux-keys > heat_key.priv\n" expect "*$*" -send -- "glance image-create --name 'ws-2012-full-agent' --is-public true --container-format ovf --disk-format qcow2 < ws-2012-full-agent.qcow2\n" +send -- "glance image-create --name 'ws-2012-full' --is-public true --container-format ovf --disk-format qcow2 < ws-2012-full.qcow2\n" expect "*$*" send -- "cd ~/keero\n" @@ -50,33 +60,22 @@ send -- "cp -Rf ~/keero/dashboard/windc /opt/stack/horizon/openstack_dashboard/d expect "*$*" send -- "cp -f ~/keero/dashboard/api/windc.py /opt/stack/horizon/openstack_dashboard/api/\n" expect "*$*" -send -- "cp -Rf ~/keero/dashboard/windcclient /opt/stack/horizon/\n" +send -- "cd ~/keero/python-portasclient\n" expect "*$*" -send -- "cd ~/keero/windc\n" +send -- "sudo python setup.py install\n" expect "*$*" -send -- "rm -rf windc.sqlite\n" +send -- "cd ~/keero/portas\n" expect "*$*" -send -- "./tools/with_venv.sh ./bin/windc-api --config-file=./etc/windc-api-paste.ini --dbsync\n" +send -- "./tools/with_venv.sh ./bin/portas-api --config-file=./etc/portas-api.conf & > ~/APIservice.log\n" +sleep 10 +send -- "\n" +expect "*$*" +send -- "cd ~/keero/conductor\n" +expect "*$*" +send -- "./tools/with_venv.sh ./bin/app.py & > ~/conductor.log\n" +sleep 10 +send -- "\n" expect "*$*" send -- "logout\n" expect "*#*" -send -- "rabbitmq-plugins enable rabbitmq_management\n" -expect "*#*" -send -- "service rabbitmq-server restart\n" -expect "*#*" -send -- "rabbitmqctl add_user keero keero\n" -expect "*#*" -send -- "rabbitmqctl set_user_tags keero administrator\n" -expect "*#*" - -send -- "su - stack\n" -expect "*$*" -send -- "cd /opt/stack/devstack\n" -expect "*$*" -send -- "source openrc admin admin\n" -expect "*$*" -send -- "cd /opt/stack/keero/windc\n" -expect "*$*" -send -- "sudo ./tools/with_venv.sh ./bin/windc-api --config-file=./etc/windc-api-paste.ini > /opt/stack/tests_windc_daemon.log &\n" -expect "*$*" From e6e9dda6778b9377f922c78e6a71b9f6e15704b9 Mon Sep 17 00:00:00 2001 From: Timur Nurlygayanov Date: Thu, 21 Mar 2013 18:09:13 +0400 Subject: [PATCH 04/14] Fixed: changed the run mode for install venv script --- conductor/tools/with_venv.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 conductor/tools/with_venv.sh diff --git a/conductor/tools/with_venv.sh b/conductor/tools/with_venv.sh old mode 100644 new mode 100755 From c8a9858ca21d1c9dd8435bc08ae49822b11618f0 Mon Sep 17 00:00:00 2001 From: Dmitry Teselkin Date: Fri, 22 Mar 2013 13:06:59 +0400 Subject: [PATCH 05/14] Code to start\stop keero components using devstack functions --- Deployment/devstack-scripts/devstack.localrc | 1 + Deployment/devstack-scripts/localrc | 2 +- Deployment/devstack-scripts/start-devstack.sh | 1 + Deployment/devstack-scripts/start-keero.sh | 25 +++++++++++++++++++ Deployment/devstack-scripts/stop-devstack.sh | 1 + Deployment/devstack-scripts/stop-keero.sh | 12 +++++++++ 6 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 Deployment/devstack-scripts/start-keero.sh create mode 100644 Deployment/devstack-scripts/stop-keero.sh diff --git a/Deployment/devstack-scripts/devstack.localrc b/Deployment/devstack-scripts/devstack.localrc index 758db5f..3295cdf 100644 --- a/Deployment/devstack-scripts/devstack.localrc +++ b/Deployment/devstack-scripts/devstack.localrc @@ -16,6 +16,7 @@ RABBIT_PASSWORD=$lab_password SERVICE_PASSWORD=$lab_password SERVICE_TOKEN=tokentoken ENABLED_SERVICES+=,heat,h-api,h-api-cfn,h-api-cw,h-eng +ENABLED_SERVICES+=,conductor,portas LOGFILE=/opt/stack/devstack/stack.sh.log SCREEN_LOGDIR=/opt/stack/log/ diff --git a/Deployment/devstack-scripts/localrc b/Deployment/devstack-scripts/localrc index 2658117..13ce3cd 100644 --- a/Deployment/devstack-scripts/localrc +++ b/Deployment/devstack-scripts/localrc @@ -1,6 +1,7 @@ #!/bin/bash DEVSTACK_DIR=/home/stack/devstack +INSTALL_DIR=/opt/stack MYSQL_DB_TMPFS=true MYSQL_DB_TMPFS_SIZE=128M @@ -8,7 +9,6 @@ MYSQL_DB_TMPFS_SIZE=128M NOVA_CACHE_TMPFS=true NOVA_CACHE_TMPFS_SIZE=24G - #====================================== source $DEVSTACK_DIR/openrc admin admin source ./functions.sh diff --git a/Deployment/devstack-scripts/start-devstack.sh b/Deployment/devstack-scripts/start-devstack.sh index 305200d..e206d87 100644 --- a/Deployment/devstack-scripts/start-devstack.sh +++ b/Deployment/devstack-scripts/start-devstack.sh @@ -20,6 +20,7 @@ $DEVSTACK_DIR/stack.sh # Executing post-stack actions #=============================================================================== source ./post-stack.sh no-localrc +source ./start-keero.sh no-localrc #=============================================================================== diff --git a/Deployment/devstack-scripts/start-keero.sh b/Deployment/devstack-scripts/start-keero.sh new file mode 100644 index 0000000..0c4aa5e --- /dev/null +++ b/Deployment/devstack-scripts/start-keero.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +if [[ -z "$1" ]] ; then + source ./localrc +fi + +die_if_not_set INSTALL_DIR + +# Starting Portas +#================ +if [[ ! -d "$INSTALL_DIR/portas" ]] ; then + mkdir -p "$INSTALL_DIR/portas" +fi + +cp "$INSTALL_DIR/keero/portas/etc" "$INSTALL_DIR/portas/etc" + +screen_it portas "cd $INSTALL_DIR/portas && portas-api --config-file=$INSTALL_DIR/portas/etc/portas-api.conf" +#================ + + + +# Starting Conductor +#=================== +screen_it conductor "cd $INSTALL_DIR/keero/conductor && bash ./tools/with_venv.sh ./bin/app.py" +#=================== diff --git a/Deployment/devstack-scripts/stop-devstack.sh b/Deployment/devstack-scripts/stop-devstack.sh index af35304..32b3d36 100644 --- a/Deployment/devstack-scripts/stop-devstack.sh +++ b/Deployment/devstack-scripts/stop-devstack.sh @@ -18,5 +18,6 @@ $DEVSTACK_DIR/unstack.sh # Executing post-unstack actions #=============================================================================== source ./post-unstack.sh no-localrc +source ./stop-keero.sh no-localrc #=============================================================================== diff --git a/Deployment/devstack-scripts/stop-keero.sh b/Deployment/devstack-scripts/stop-keero.sh new file mode 100644 index 0000000..bf8af5f --- /dev/null +++ b/Deployment/devstack-scripts/stop-keero.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +if [[ -z "$1" ]] ; then + source ./localrc +fi + +# Stopping Keero components +#========================== +for serv in conductor portas ; do + screen -S $SCREEN_NAME -p $serv -X kill +done +#========================== From eaddba5640012947e9062bef35f14303e21e0ad3 Mon Sep 17 00:00:00 2001 From: Timur Nurlygayanov Date: Mon, 25 Mar 2013 11:52:03 +0400 Subject: [PATCH 06/14] Fixed automated tests for WebUI. Added class Page with simple objects. --- tests/selenium/datacenters_page.py | 52 ++++-------- tests/selenium/login_page.py | 25 ++---- tests/selenium/page.py | 130 +++++++++++++++++++++++++++++ tests/selenium/services_page.py | 54 ++++-------- 4 files changed, 169 insertions(+), 92 deletions(-) create mode 100644 tests/selenium/page.py diff --git a/tests/selenium/datacenters_page.py b/tests/selenium/datacenters_page.py index e48a9c1..7c32cce 100644 --- a/tests/selenium/datacenters_page.py +++ b/tests/selenium/datacenters_page.py @@ -1,56 +1,36 @@ import re -from login_page import LoginPage from services_page import ServicesPage +import page -class DataCentersPage(): +class DataCentersPage(page.Page): page = None - def __init__(self): - start_page = LoginPage() - self.page = start_page.login() - self.page.find_element_by_link_text('Project').click() - self.page.find_element_by_link_text('Windows Data Centers').click() - def create_data_center(self, name): - button_text = 'Create Windows Data Center' - self.page.find_element_by_link_text(button_text).click() - name_field = self.page.find_element_by_id('id_name') + self.Button('Create Windows Data Center').Click() + + self.EditBox('id_name').Set(name) xpath = "//input[@value='Create']" - button = self.page.find_element_by_xpath(xpath) + self.Button(xpath).Click() - name_field.clear() - name_field.send_keys(name) - - button.click() - - return self.page - - def find_data_center(self, name): - return self.page.find_element_by_link_text(name) + return self def delete_data_center(self, name): - datacenter = self.find_data_center(name) - link = datacenter.get_attribute('href') + link = self.Link(name).Address() datacenter_id = re.search('windc/(\S+)', link).group(0)[6:-1] xpath = ".//*[@id='windc__row__%s']/td[3]/div/a[2]" % datacenter_id - more_button = self.page.find_element_by_xpath(xpath) + self.Button(xpath).Click() - more_button.click() + button_id = "windc__row_%s__action_delete" % datacenter_id + self.Button(button_id).Click() - delete_button_id = "windc__row_%s__action_delete" % datacenter_id - delete_button = self.page.find_element_by_id(delete_button_id) + self.Button("Delete Data Center").Click() - delete_button.click() - - self.page.find_element_by_link_text("Delete Data Center").click() - - return self.page + return self def select_data_center(self, name): - datacenter = self.page.find_data_center(name) - datacenter.click() - self.page = ServicesPage(self.page) - return self.page + self.Link(name).Click() + page = ServicesPage(self.driver) + return page diff --git a/tests/selenium/login_page.py b/tests/selenium/login_page.py index f0f357c..b22c9b1 100644 --- a/tests/selenium/login_page.py +++ b/tests/selenium/login_page.py @@ -1,8 +1,8 @@ import ConfigParser -from selenium import webdriver +import page -class LoginPage(): +class LoginPage(page.Page): def login(self): config = ConfigParser.RawConfigParser() @@ -11,20 +11,11 @@ class LoginPage(): user = config.get('server', 'user') password = config.get('server', 'password') - page = webdriver.Firefox() - page.set_page_load_timeout(30) - page.implicitly_wait(30) - page.get(url) - name = page.find_element_by_name('username') - pwd = page.find_element_by_name('password') + self.Open(url) + + self.EditBox('username').Set(user) + self.EditBox('password').Set(password) xpath = "//button[@type='submit']" - button = page.find_element_by_xpath(xpath) + self.Button(xpath).Click() - name.clear() - name.send_keys(user) - pwd.clear() - pwd.send_keys(password) - - button.click() - - return page + return self diff --git a/tests/selenium/page.py b/tests/selenium/page.py new file mode 100644 index 0000000..e2dcb56 --- /dev/null +++ b/tests/selenium/page.py @@ -0,0 +1,130 @@ +from selenium import webdriver + + +class ButtonClass: + button = None + + def __init__(self, object): + self.button = object + + def Click(self): + self.button.click() + + def isPresented(self): + if self.button != None: + return True + return False + + +class LinkClass: + link = None + + def __init__(self, object): + self.link = object + + def Click(self): + self.link.click() + + def isPresented(self): + if self.link != None: + return True + return False + + def Address(self): + return self.link.get_attribute('href') + + +class EditBoxClass: + edit = None + + def __init__(self, object): + self.edit = object + + def isPresented(self): + if self.edit != None: + return True + return False + + def Set(self, value): + self.edit.clear() + self.edit.send_keys(value) + + def Text(self): + return self.edit.get_text() + + +class DropDownListClass: + select = None + + def __init__(self, object): + self.select = object + + def isPresented(self): + if self.select != None: + return True + return False + + def Set(self, value): + self.select.select_by_visible_text(value) + + def Text(self): + return self.select.get_text() + + +class Page: + + driver = None + timeout = 30 + + def __init__(self, driver): + driver.set_page_load_timeout(30) + driver.implicitly_wait(30) + self.driver = driver + + def _find_element(self, parameter): + object = None + try: + object = self.driver.find_element_by_name(parameter) + return object + except: + pass + try: + object = self.driver.find_element_by_id(parameter) + return object + except: + pass + try: + object = self.driver.find_element_by_xpath(parameter) + return object + except: + pass + try: + object = self.driver.find_element_by_link_text(parameter) + return object + except: + pass + + return object + + def Open(self, url): + self.driver.get(url) + + def Button(self, name): + object = self._find_element(name) + button = ButtonClass(object) + return button + + def Link(self, name): + object = self._find_element(name) + link = LinkClass(object) + return link + + def EditBox(self, name): + object = self._find_element(name) + edit = EditBoxClass(object) + return edit + + def DropDownList(self, name): + object = self._find_element(name) + select = DropDownListClass(object) + return select \ No newline at end of file diff --git a/tests/selenium/services_page.py b/tests/selenium/services_page.py index fb43043..e8ea9f8 100644 --- a/tests/selenium/services_page.py +++ b/tests/selenium/services_page.py @@ -1,57 +1,33 @@ -import ConfigParser -from selenium import webdriver +import page +import re -class ServicesPage(): - page = None - - def __init__(self, page): - self.page = page +class ServicesPage(page.Page): def create_service(self, service_type, parameters): - button_id = 'services__action_CreateService' - button = self.page.find_element_by_id(button_id) - button.click() - - self.select_type_of_service(service_type) + self.Button('services__action_CreateService').Click() + self.DropDownList('0-service').Set(service_type) + self.Button('wizard_goto_step').Click() for parameter in parameters: - field = self.page.find_element_by_name(parameter.key) - field.clear() - field.send_keys(parameter.value) + self.EditBox(parameter.key).Set(parameter.value) - xpath = "//input[@value='Deploy']" - deploy_button = self.page.find_element_by_xpath(xpath) - deploy_button.click() + self.Button("//input[@value='Create']").Click() - return page - - def select_type_of_service(self, service_type): - type_field = self.page.find_element_by_name('0-service') - type_field.select_by_visible_text(service_type) - next_button = self.page.find_element_by_name('wizard_goto_step') - next_button.click() - return self.page - - def find_service(self, name): - return self.page.find_element_by_link_text(name) + return self def delete_service(self, name): - service = self.find_data_center(name) - link = service.get_attribute('href') + link = self.Link(name).Address() service_id = re.search('windc/(\S+)', link).group(0)[6:-1] xpath = ".//*[@id='services__row__%s']/td[5]/div/a[2]" % service_id - more_button = self.page.find_element_by_xpath(xpath) - more_button.click() + self.Button(xpath).Click() - delete_button_id = "services__row_%s__action_delete" % datacenter_id - delete_button = self.page.find_element_by_id(delete_button_id) + button_id = "services__row_%s__action_delete" % service_id + self.Button(button_id).Click() - delete_button.click() + self.Button("Delete Service").Click() - self.page.find_element_by_link_text("Delete Service").click() - - return self.page + return self From c13879946562f8fb6a2b66251871e5a57cb365d5 Mon Sep 17 00:00:00 2001 From: Timur Nurlygayanov Date: Mon, 25 Mar 2013 15:04:10 +0400 Subject: [PATCH 07/14] Fixed automated tests for web UI. --- tests/selenium/conf.ini | 2 +- tests/selenium/datacenters_page.py | 4 +- tests/selenium/page.py | 111 +++++++++++++++-------------- tests/selenium/test.py | 36 ++++++---- 4 files changed, 84 insertions(+), 69 deletions(-) diff --git a/tests/selenium/conf.ini b/tests/selenium/conf.ini index 8b43288..437aeba 100644 --- a/tests/selenium/conf.ini +++ b/tests/selenium/conf.ini @@ -1,4 +1,4 @@ [server] address=http://172.18.124.101 user=admin -password=AkvareL707 \ No newline at end of file +password=swordfish \ No newline at end of file diff --git a/tests/selenium/datacenters_page.py b/tests/selenium/datacenters_page.py index 7c32cce..f0e74a8 100644 --- a/tests/selenium/datacenters_page.py +++ b/tests/selenium/datacenters_page.py @@ -20,7 +20,9 @@ class DataCentersPage(page.Page): link = self.Link(name).Address() datacenter_id = re.search('windc/(\S+)', link).group(0)[6:-1] - xpath = ".//*[@id='windc__row__%s']/td[3]/div/a[2]" % datacenter_id + print 'Data Center ID: ' + datacenter_id + + xpath = ".//*[@id='windc__row__%s']/td[4]/div/a[2]" % datacenter_id self.Button(xpath).Click() button_id = "windc__row_%s__action_delete" % datacenter_id diff --git a/tests/selenium/page.py b/tests/selenium/page.py index e2dcb56..80085ab 100644 --- a/tests/selenium/page.py +++ b/tests/selenium/page.py @@ -1,11 +1,10 @@ -from selenium import webdriver class ButtonClass: button = None - def __init__(self, object): - self.button = object + def __init__(self, obj): + self.button = obj def Click(self): self.button.click() @@ -19,8 +18,8 @@ class ButtonClass: class LinkClass: link = None - def __init__(self, object): - self.link = object + def __init__(self, obj): + self.link = obj def Click(self): self.link.click() @@ -35,10 +34,9 @@ class LinkClass: class EditBoxClass: - edit = None - def __init__(self, object): - self.edit = object + def __init__(self, obj): + self.edit = obj def isPresented(self): if self.edit != None: @@ -56,8 +54,8 @@ class EditBoxClass: class DropDownListClass: select = None - def __init__(self, object): - self.select = object + def __init__(self, obj): + self.select = obj def isPresented(self): if self.select != None: @@ -72,59 +70,68 @@ class DropDownListClass: class Page: - + driver = None - timeout = 30 - + timeout = 300 + def __init__(self, driver): driver.set_page_load_timeout(30) - driver.implicitly_wait(30) + driver.implicitly_wait(0.01) self.driver = driver - + def _find_element(self, parameter): - object = None - try: - object = self.driver.find_element_by_name(parameter) - return object - except: - pass - try: - object = self.driver.find_element_by_id(parameter) - return object - except: - pass - try: - object = self.driver.find_element_by_xpath(parameter) - return object - except: - pass - try: - object = self.driver.find_element_by_link_text(parameter) - return object - except: - pass - - return object - + obj = None + k = 0 + while (obj == None and k < self.timeout): + k += 1 + try: + obj = self.driver.find_element_by_name(parameter) + return obj + except: + pass + try: + obj = self.driver.find_element_by_id(parameter) + return obj + except: + pass + try: + obj = self.driver.find_element_by_xpath(parameter) + return obj + except: + pass + try: + obj = self.driver.find_element_by_partial_link_text(parameter) + return obj + except: + pass + + return obj + def Open(self, url): self.driver.get(url) - + def Button(self, name): - object = self._find_element(name) - button = ButtonClass(object) + obj = self._find_element(name) + button = ButtonClass(obj) return button - + def Link(self, name): - object = self._find_element(name) - link = LinkClass(object) + obj = self._find_element(name) + link = LinkClass(obj) return link - + def EditBox(self, name): - object = self._find_element(name) - edit = EditBoxClass(object) + obj = self._find_element(name) + edit = EditBoxClass(obj) return edit - + def DropDownList(self, name): - object = self._find_element(name) - select = DropDownListClass(object) - return select \ No newline at end of file + obj = self._find_element(name) + select = DropDownListClass(obj) + return select + + def Navigate(self, path): + steps = path.split(':') + + for step in steps: + self.Button(step).Click() diff --git a/tests/selenium/test.py b/tests/selenium/test.py index 6c8389c..4391a0b 100644 --- a/tests/selenium/test.py +++ b/tests/selenium/test.py @@ -1,54 +1,60 @@ # -*- coding: utf-8 -*- -import untitest2 +import unittest2 +from login_page import LoginPage from datacenters_page import DataCentersPage +from selenium import webdriver class SanityTests(unittest2.TestCase): def setUp(self): - self.page = DataCentersPage() + driver = webdriver.Firefox() + self.page = LoginPage(driver) + self.page.login() + self.page.Navigate('Project:Windows Data Centers') + self.page = DataCentersPage(driver) def tearDown(self): - self.page.close() + self.page.driver.close() def test_01_create_data_center(self): self.page.create_data_center('dc1') - assert self.page.find_data_center('dc1') is not None + assert self.page.Link('dc1').isPresented() def test_02_delete_data_center(self): self.page.delete_data_center('dc1') - assert self.page.find_data_center('dc1') is None + assert not self.page.Link('dc1').isPresented() def test_03_create_data_centers(self): for i in range(1, 20): name = 'datacenter' + str(i) self.page.create_data_center(name) - assert self.page.find_data_center(name) is not None + assert self.page.Link(name).isPresented() def test_04_delete_data_centers(self): self.page.delete_data_center('datacenter1') self.page.delete_data_center('datacenter20') - assert self.page.find_data_center('datacenter1') is None - assert self.page.find_data_center('datacenter20') is None + assert not self.page.Link('datacenter1').isPresented() + assert not self.page.Link('datacenter20').isPresented() for i in range(2, 19): name = 'datacenter' + str(i) - assert self.page.find_data_center(name) is not None + assert self.page.Link(name).isPresented() def test_05_create_service_ad(self): name = 'dc001.local' - self.page.create_data_center(name) - self.select_data_center(name) - + self.page.create_data_center('test') + self.page.select_data_center('test') + ad_parameters = {'1-dc_name': name, '1-dc_count': 1, '1-adm_password': 'AkvareL707!', '1-recovery_password': 'AkvareL707!'} self.page.create_service('Active Directory', ad_parameters) - - assert self.page.find_service(name) is not None + + assert self.page.Link(name).isPresented() if __name__ == '__main__': - unittest2.main() \ No newline at end of file + unittest2.main() From bb3e62bb4d5060c344e171f304194ce8bd8c2fc9 Mon Sep 17 00:00:00 2001 From: Timur Nurlygayanov Date: Tue, 26 Mar 2013 06:35:35 +0700 Subject: [PATCH 08/14] Fixed all pep8. --- conductor/bin/app.py | 2 +- conductor/conductor/app.py | 7 +- conductor/conductor/cloud_formation.py | 1 - .../conductor/commands/cloud_formation.py | 1 - conductor/conductor/commands/dispatcher.py | 1 - conductor/conductor/commands/windows_agent.py | 1 - conductor/conductor/function_context.py | 2 +- conductor/conductor/helpers.py | 1 + conductor/conductor/rabbitmq.py | 6 +- conductor/conductor/reporting.py | 5 +- conductor/conductor/windows_agent.py | 8 +- conductor/conductor/workflow.py | 3 +- conductor/conductor/xml_code_engine.py | 3 +- portas/portas/api/middleware/context.py | 4 +- portas/portas/api/v1/__init__.py | 28 ++++--- portas/portas/api/v1/active_directories.py | 30 ++++--- portas/portas/api/v1/environments.py | 5 +- portas/portas/api/v1/router.py | 17 ++-- portas/portas/api/v1/sessions.py | 55 ++++++++---- portas/portas/api/v1/webservers.py | 24 ++++-- portas/portas/common/config.py | 1 + portas/portas/common/exception.py | 3 +- portas/portas/common/service.py | 22 +++-- portas/portas/common/uuidutils.py | 2 +- portas/portas/context.py | 6 +- portas/portas/db/__init__.py | 2 +- .../versions/001_add_initial_tables.py | 4 +- .../versions/002_add_session_table.py | 5 +- .../versions/003_add_status_table.py | 5 +- .../005_remove_obsolete_service_table.py | 17 ++-- portas/portas/db/models.py | 3 +- portas/portas/utils.py | 6 +- python-portasclient/portasclient/version.py | 2 +- python-portasclient/tests/test_sanity.py | 84 ++++++++----------- 34 files changed, 203 insertions(+), 163 deletions(-) diff --git a/conductor/bin/app.py b/conductor/bin/app.py index 3c2619b..bb7624b 100644 --- a/conductor/bin/app.py +++ b/conductor/bin/app.py @@ -1,3 +1,3 @@ #!/usr/bin/env python -from conductor import app \ No newline at end of file +from conductor import app diff --git a/conductor/conductor/app.py b/conductor/conductor/app.py index f4cf9a7..5e241c7 100644 --- a/conductor/conductor/app.py +++ b/conductor/conductor/app.py @@ -41,12 +41,14 @@ def task_received(task, message_id): def loop(callback): for workflow in workflows: workflow.execute() - if not command_dispatcher.execute_pending(lambda: schedule(loop, callback)): + func = lambda: schedule(loop, callback) + if not command_dispatcher.execute_pending(func): callback() def shutdown(): command_dispatcher.close() - rmqclient.send('task-results', json.dumps(task), message_id=message_id) + rmqclient.send('task-results', json.dumps(task), + message_id=message_id) print 'Finished at', datetime.datetime.now() loop(shutdown) @@ -61,4 +63,3 @@ def start(): rmqclient.start(start) tornado.ioloop.IOLoop.instance().start() - diff --git a/conductor/conductor/cloud_formation.py b/conductor/conductor/cloud_formation.py index 3ef3b41..95fb9e4 100644 --- a/conductor/conductor/cloud_formation.py +++ b/conductor/conductor/cloud_formation.py @@ -36,4 +36,3 @@ xml_code_engine.XmlCodeEngine.register_function( xml_code_engine.XmlCodeEngine.register_function( prepare_user_data, "prepare_user_data") - diff --git a/conductor/conductor/commands/cloud_formation.py b/conductor/conductor/commands/cloud_formation.py index 0d12083..262a1f2 100644 --- a/conductor/conductor/commands/cloud_formation.py +++ b/conductor/conductor/commands/cloud_formation.py @@ -59,7 +59,6 @@ class HeatExecutor(CommandBase): self._stack ]) - callbacks = [] for t in self._pending_list: if t['callback']: diff --git a/conductor/conductor/commands/dispatcher.py b/conductor/conductor/commands/dispatcher.py index b815ddb..97db0ef 100644 --- a/conductor/conductor/commands/dispatcher.py +++ b/conductor/conductor/commands/dispatcher.py @@ -32,7 +32,6 @@ class CommandDispatcher(command.CommandBase): return result > 0 - def has_pending_commands(self): result = False for command in self._command_map.values(): diff --git a/conductor/conductor/commands/windows_agent.py b/conductor/conductor/commands/windows_agent.py index c4747b6..b0abbcd 100644 --- a/conductor/conductor/commands/windows_agent.py +++ b/conductor/conductor/commands/windows_agent.py @@ -63,4 +63,3 @@ class WindowsAgentExecutor(CommandBase): def close(self): self._rmqclient.unsubscribe('-execution-results') - diff --git a/conductor/conductor/function_context.py b/conductor/conductor/function_context.py index 237f23e..e27b6db 100644 --- a/conductor/conductor/function_context.py +++ b/conductor/conductor/function_context.py @@ -48,4 +48,4 @@ class Context(object): return str(self._data) if self._parent: return str(self._parent) - return str({}) \ No newline at end of file + return str({}) diff --git a/conductor/conductor/helpers.py b/conductor/conductor/helpers.py index 4128e16..435a35b 100644 --- a/conductor/conductor/helpers.py +++ b/conductor/conductor/helpers.py @@ -38,6 +38,7 @@ def merge_dicts(dict1, dict2, max_levels=0): result[key] = value return result + def find(f, seq): """Return first item in sequence where f(item) == True.""" index = 0 diff --git a/conductor/conductor/rabbitmq.py b/conductor/conductor/rabbitmq.py index d7c3351..8a9cebe 100644 --- a/conductor/conductor/rabbitmq.py +++ b/conductor/conductor/rabbitmq.py @@ -54,7 +54,8 @@ class RabbitMqClient(object): del self._subscriptions[queue] def start(self, callback=None): - if IOLoop is None: raise ImportError("Tornado not installed") + if IOLoop is None: + raise ImportError("Tornado not installed") self._started_callback = callback ioloop = IOLoop.instance() self.timeout_id = ioloop.add_timeout(time.time() + 0.1, @@ -67,6 +68,3 @@ class RabbitMqClient(object): callback=lambda frame: self._channel.basic_publish( exchange=exchange, routing_key=queue, body=data, properties=properties)) - - - diff --git a/conductor/conductor/reporting.py b/conductor/conductor/reporting.py index 4dbef12..7d1a3d4 100644 --- a/conductor/conductor/reporting.py +++ b/conductor/conductor/reporting.py @@ -18,12 +18,9 @@ class Reporter(object): self._rmqclient.send( queue='task-reports', data=msg, message_id=self._task_id) + def _report_func(context, id, entity, text, **kwargs): reporter = context['/reporter'] return reporter._report_func(id, entity, text, **kwargs) xml_code_engine.XmlCodeEngine.register_function(_report_func, "report") - - - - diff --git a/conductor/conductor/windows_agent.py b/conductor/conductor/windows_agent.py index 287abb0..ba916ba 100644 --- a/conductor/conductor/windows_agent.py +++ b/conductor/conductor/windows_agent.py @@ -3,11 +3,13 @@ import xml_code_engine def send_command(engine, context, body, template, host, mappings=None, result=None, **kwargs): - if not mappings: mappings = {} + if not mappings: + mappings = {} command_dispatcher = context['/commandDispatcher'] def callback(result_value): - print "Received result for %s: %s. Body is %s" % (template, result_value, body) + msg = "Received result for %s: %s. Body is %s" + print msg % (template, result_value, body) if result is not None: context[result] = result_value['Result'] @@ -22,4 +24,4 @@ def send_command(engine, context, body, template, host, mappings=None, callback=callback) -xml_code_engine.XmlCodeEngine.register_function(send_command, "send-command") \ No newline at end of file +xml_code_engine.XmlCodeEngine.register_function(send_command, "send-command") diff --git a/conductor/conductor/workflow.py b/conductor/conductor/workflow.py index a39a7da..46d1d3d 100644 --- a/conductor/conductor/workflow.py +++ b/conductor/conductor/workflow.py @@ -5,6 +5,7 @@ import re import xml_code_engine import function_context + class Workflow(object): def __init__(self, filename, data, command_dispatcher, config, reporter): self._data = data @@ -84,7 +85,6 @@ class Workflow(object): else: return position + suffix.split('.') - @staticmethod def _select_func(context, path='', source=None, **kwargs): @@ -102,7 +102,6 @@ class Workflow(object): context['/dataSource'], Workflow._correct_position(path, context)) - @staticmethod def _set_func(path, context, body, engine, target=None, **kwargs): body_data = engine.evaluate_content(body, context) diff --git a/conductor/conductor/xml_code_engine.py b/conductor/conductor/xml_code_engine.py index fe676b0..42c18a1 100644 --- a/conductor/conductor/xml_code_engine.py +++ b/conductor/conductor/xml_code_engine.py @@ -61,7 +61,8 @@ class XmlCodeEngine(object): return_value = result if len(result) == 0: return_value = ''.join(parts) - if do_strip: return_value = return_value.strip() + if do_strip: + return_value = return_value.strip() elif len(result) == 1: return_value = result[0] diff --git a/portas/portas/api/middleware/context.py b/portas/portas/api/middleware/context.py index cd0d6a7..fc81c5c 100644 --- a/portas/portas/api/middleware/context.py +++ b/portas/portas/api/middleware/context.py @@ -75,7 +75,7 @@ class ContextMiddleware(BaseContextMiddleware): 'auth_tok': req.headers.get('X-Auth-Token', deprecated_token), 'service_catalog': service_catalog, 'session': req.headers.get('X-Configuration-Session') - } + } req.context = portas.context.RequestContext(**kwargs) else: raise webob.exc.HTTPUnauthorized() @@ -84,4 +84,4 @@ class ContextMiddleware(BaseContextMiddleware): def factory(cls, global_conf, **local_conf): def filter(app): return cls(app) - return filter \ No newline at end of file + return filter diff --git a/portas/portas/api/v1/__init__.py b/portas/portas/api/v1/__init__.py index 6fa090e..2c08d56 100644 --- a/portas/portas/api/v1/__init__.py +++ b/portas/portas/api/v1/__init__.py @@ -27,15 +27,19 @@ def get_env_status(environment_id, session_id): unit = get_session() if not session_id: - session = unit.query(Session).filter( - Session.environment_id == environment_id and Session.state.in_(['open', 'deploying'])).first() + variants = ['open', 'deploying'] + session = unit.query(Session).filter(Session.environment_id == + environment_id and + Session.state.in_(variants) + ).first() if session: session_id = session.id else: return status session_state = unit.query(Session).get(session_id).state - reports_count = unit.query(Status).filter_by(environment_id=environment_id, session_id=session_id).count() + reports_count = unit.query(Status).filter_by(environment_id=environment_id, + session_id=session_id).count() if session_state == 'deployed': status = 'finished' @@ -50,13 +54,16 @@ def get_env_status(environment_id, session_id): def get_statuses(type): if type in draft['services']: - return [get_service_status(environment_id, session_id, service) for service in - draft['services'][type]] + services = draft['services'][type] + return [get_service_status(environment_id, + session_id, + service) for service in services] else: return [] is_inprogress = filter(lambda item: item == 'inprogress', - get_statuses('activeDirectories') + get_statuses('webServers')) + get_statuses('activeDirectories') + + get_statuses('webServers')) if session_state == 'deploying' and is_inprogress > 1: status = 'inprogress' @@ -71,10 +78,11 @@ def get_service_status(environment_id, session_id, service): session_state = unit.query(Session).get(session_id).state entities = [u['id'] for u in service['units']] - reports_count = unit.query(Status).filter(Status.environment_id == environment_id - and Status.session_id == session_id - and Status.entity_id.in_(entities)) \ - .count() + reports_count = unit.query(Status).filter( + Status.environment_id == environment_id + and Status.session_id == session_id + and Status.entity_id.in_(entities) + ).count() if session_state == 'deployed': status = 'finished' diff --git a/portas/portas/api/v1/active_directories.py b/portas/portas/api/v1/active_directories.py index 2b57a67..bacdb2a 100644 --- a/portas/portas/api/v1/active_directories.py +++ b/portas/portas/api/v1/active_directories.py @@ -9,18 +9,23 @@ log = logging.getLogger(__name__) class Controller(object): def index(self, request, environment_id): - log.debug(_('ActiveDirectory:Index '.format(environment_id))) + log.debug(_('ActiveDirectory:Index '. + format(environment_id))) - draft = prepare_draft(get_draft(environment_id, request.context.session)) + draft = prepare_draft(get_draft(environment_id, + request.context.session)) for dc in draft['services']['activeDirectories']: - dc['status'] = get_service_status(environment_id, request.context.session, dc) + dc['status'] = get_service_status(environment_id, + request.context.session, + dc) return {'activeDirectories': draft['services']['activeDirectories']} @utils.verify_session def create(self, request, environment_id, body): - log.debug(_('ActiveDirectory:Create '.format(environment_id, body))) + log.debug(_('ActiveDirectory:Create '. + format(environment_id, body))) draft = get_draft(session_id=request.context.session) @@ -33,7 +38,8 @@ class Controller(object): for unit in active_directory['units']: unit_count += 1 unit['id'] = uuidutils.generate_uuid() - unit['name'] = 'dc{0}{1}'.format(unit_count, active_directory['id'][:4]) + unit['name'] = 'dc{0}{1}'.format(unit_count, + active_directory['id'][:4]) draft = prepare_draft(draft) draft['services']['activeDirectories'].append(active_directory) @@ -42,23 +48,25 @@ class Controller(object): return active_directory def delete(self, request, environment_id, active_directory_id): - log.debug(_('ActiveDirectory:Delete '.format(environment_id, active_directory_id))) + log.debug(_('ActiveDirectory:Delete '. + format(environment_id, active_directory_id))) draft = get_draft(request.context.session) - draft['services']['activeDirectories'] = [service for service in draft['services']['activeDirectories'] if - service['id'] != active_directory_id] + items = [service for service in draft['services']['activeDirectories'] + if service['id'] != active_directory_id] + draft['services']['activeDirectories'] = items save_draft(request.context.session, draft) def prepare_draft(draft): - if not draft.has_key('services'): + if not 'services' in draft: draft['services'] = {} - if not draft['services'].has_key('activeDirectories'): + if not 'activeDirectories' in draft['services']: draft['services']['activeDirectories'] = [] return draft def create_resource(): - return wsgi.Resource(Controller()) \ No newline at end of file + return wsgi.Resource(Controller()) diff --git a/portas/portas/api/v1/environments.py b/portas/portas/api/v1/environments.py index e8c82ee..4129bbf 100644 --- a/portas/portas/api/v1/environments.py +++ b/portas/portas/api/v1/environments.py @@ -61,7 +61,8 @@ class Controller(object): return env def update(self, request, environment_id, body): - log.debug(_('Environments:Update '.format(environment_id, body))) + log.debug(_('Environments:Update '. + format(environment_id, body))) session = get_session() environment = session.query(Environment).get(environment_id) @@ -88,4 +89,4 @@ class Controller(object): def create_resource(): - return wsgi.Resource(Controller()) \ No newline at end of file + return wsgi.Resource(Controller()) diff --git a/portas/portas/api/v1/router.py b/portas/portas/api/v1/router.py index 5a18601..ed0da25 100644 --- a/portas/portas/api/v1/router.py +++ b/portas/portas/api/v1/router.py @@ -16,7 +16,8 @@ # under the License. import routes from portas.openstack.common import wsgi -from portas.api.v1 import environments, sessions, active_directories, webservers +from portas.api.v1 import (environments, sessions, + active_directories, webservers) class API(wsgi.Router): @@ -64,11 +65,13 @@ class API(wsgi.Router): controller=sessions_resource, action='delete', conditions={'method': ['DELETE']}) - mapper.connect('/environments/{environment_id}/sessions/{session_id}/reports', + mapper.connect('/environments/{environment_id}/sessions/' + '{session_id}/reports', controller=sessions_resource, action='reports', conditions={'method': ['GET']}) - mapper.connect('/environments/{environment_id}/sessions/{session_id}/deploy', + mapper.connect('/environments/{environment_id}/sessions/' + '{session_id}/deploy', controller=sessions_resource, action='deploy', conditions={'method': ['POST']}) @@ -82,7 +85,8 @@ class API(wsgi.Router): controller=activeDirectories_resource, action='create', conditions={'method': ['POST']}) - mapper.connect('/environments/{environment_id}/activeDirectories/{active_directory_id}', + mapper.connect('/environments/{environment_id}/activeDirectories/' + '{active_directory_id}', controller=activeDirectories_resource, action='delete', conditions={'method': ['DELETE']}) @@ -96,8 +100,9 @@ class API(wsgi.Router): controller=webServers_resource, action='create', conditions={'method': ['POST']}) - mapper.connect('/environments/{environment_id}/webServers/{web_server_id}', + mapper.connect('/environments/{environment_id}/webServers/' + '{web_server_id}', controller=webServers_resource, action='delete', conditions={'method': ['DELETE']}) - super(API, self).__init__(mapper) \ No newline at end of file + super(API, self).__init__(mapper) diff --git a/portas/portas/api/v1/sessions.py b/portas/portas/api/v1/sessions.py index dd12cea..5bf52b0 100644 --- a/portas/portas/api/v1/sessions.py +++ b/portas/portas/api/v1/sessions.py @@ -17,34 +17,44 @@ log = logging.getLogger(__name__) class Controller(object): def __init__(self): self.write_lock = Semaphore(1) - connection = amqp.Connection('{0}:{1}'.format(rabbitmq.host, rabbitmq.port), virtual_host=rabbitmq.virtual_host, - userid=rabbitmq.userid, password=rabbitmq.password, + connection = amqp.Connection('{0}:{1}'. + format(rabbitmq.host, rabbitmq.port), + virtual_host=rabbitmq.virtual_host, + userid=rabbitmq.userid, + password=rabbitmq.password, ssl=rabbitmq.use_ssl, insist=True) self.ch = connection.channel() - self.ch.exchange_declare('tasks', 'direct', durable=True, auto_delete=False) + self.ch.exchange_declare('tasks', 'direct', durable=True, + auto_delete=False) def index(self, request, environment_id): log.debug(_('Session:List '.format(environment_id))) - filters = {'environment_id': environment_id, 'user_id': request.context.user} + filters = {'environment_id': environment_id, + 'user_id': request.context.user} unit = get_session() configuration_sessions = unit.query(Session).filter_by(**filters) - return {"sessions": [session.to_dict() for session in configuration_sessions if - session.environment.tenant_id == request.context.tenant]} + sessions = [session.to_dict() for session in configuration_sessions if + session.environment.tenant_id == request.context.tenant] + return {"sessions": sessions} def configure(self, request, environment_id): log.debug(_('Session:Configure '.format(environment_id))) - params = {'environment_id': environment_id, 'user_id': request.context.user, 'state': 'open'} + params = {'environment_id': environment_id, + 'user_id': request.context.user, + 'state': 'open'} session = Session() session.update(params) unit = get_session() - if unit.query(Session).filter(Session.environment_id == environment_id and Session.state.in_( - ['open', 'deploing'])).first(): + if unit.query(Session).filter(Session.environment_id == environment_id + and + Session.state.in_(['open', 'deploing']) + ).first(): log.info('There is already open session for this environment') raise exc.HTTPConflict @@ -58,7 +68,8 @@ class Controller(object): return session.to_dict() def show(self, request, environment_id, session_id): - log.debug(_('Session:Show '.format(environment_id, session_id))) + log.debug(_('Session:Show '. + format(environment_id, session_id))) unit = get_session() session = unit.query(Session).get(session_id) @@ -70,14 +81,16 @@ class Controller(object): return session.to_dict() def delete(self, request, environment_id, session_id): - log.debug(_('Session:Delete '.format(environment_id, session_id))) + log.debug(_('Session:Delete '. + format(environment_id, session_id))) unit = get_session() session = unit.query(Session).get(session_id) + comment = 'Session object in \'deploying\' state could not be deleted' if session.state == 'deploying': - log.info('Session is in \'deploying\' state. Could not be deleted.') - raise exc.HTTPForbidden(comment='Session object in \'deploying\' state could not be deleted') + log.info(comment) + raise exc.HTTPForbidden(comment=comment) with unit.begin(): unit.delete(session) @@ -85,7 +98,8 @@ class Controller(object): return None def reports(self, request, environment_id, session_id): - log.debug(_('Session:Reports '.format(environment_id, session_id))) + log.debug(_('Session:Reports '. + format(environment_id, session_id))) unit = get_session() statuses = unit.query(Status).filter_by(session_id=session_id) @@ -93,20 +107,25 @@ class Controller(object): return {'reports': [status.to_dict() for status in statuses]} def deploy(self, request, environment_id, session_id): - log.debug(_('Session:Deploy '.format(environment_id, session_id))) + log.debug(_('Session:Deploy '. + format(environment_id, session_id))) unit = get_session() session = unit.query(Session).get(session_id) + msg = _('Could not deploy session. Session is already ' + 'deployed or in deployment state') if session.state != 'open': - log.warn(_('Could not deploy session. Session is already deployed or in deployment state')) + log.warn(msg) session.state = 'deploying' session.save(unit) with self.write_lock: - self.ch.basic_publish(Message(body=anyjson.serialize(session.description)), 'tasks', 'tasks') + self.ch.basic_publish(Message(body=anyjson. + serialize(session.description)), + 'tasks', 'tasks') def create_resource(): - return wsgi.Resource(Controller()) \ No newline at end of file + return wsgi.Resource(Controller()) diff --git a/portas/portas/api/v1/webservers.py b/portas/portas/api/v1/webservers.py index d1af6bc..ef1344f 100644 --- a/portas/portas/api/v1/webservers.py +++ b/portas/portas/api/v1/webservers.py @@ -11,16 +11,19 @@ class Controller(object): def index(self, request, environment_id): log.debug(_('WebServer:List '.format(environment_id))) - draft = prepare_draft(get_draft(environment_id, request.context.session)) + draft = prepare_draft(get_draft(environment_id, + request.context.session)) for dc in draft['services']['webServers']: - dc['status'] = get_service_status(environment_id, request.context.session, dc) + dc['status'] = get_service_status(environment_id, + request.context.session, dc) return {'webServers': draft['services']['webServers']} @utils.verify_session def create(self, request, environment_id, body): - log.debug(_('WebServer:Create '.format(environment_id, body))) + log.debug(_('WebServer:Create '. + format(environment_id, body))) draft = get_draft(session_id=request.context.session) @@ -43,23 +46,26 @@ class Controller(object): @utils.verify_session def delete(self, request, environment_id, web_server_id): - log.debug(_('WebServer:Delete '.format(environment_id, web_server_id))) + log.debug(_('WebServer:Delete '. + format(environment_id, web_server_id))) draft = get_draft(session_id=request.context.session) - draft['services']['webServers'] = [service for service in draft['services']['webServers'] if - service['id'] != web_server_id] + + elements = [service for service in draft['services']['webServers'] if + service['id'] != web_server_id] + draft['services']['webServers'] = elements save_draft(request.context.session, draft) def prepare_draft(draft): - if not draft.has_key('services'): + if not 'services' in draft: draft['services'] = {} - if not draft['services'].has_key('webServers'): + if not 'webServers' in draft['services']: draft['services']['webServers'] = [] return draft def create_resource(): - return wsgi.Resource(Controller()) \ No newline at end of file + return wsgi.Resource(Controller()) diff --git a/portas/portas/common/config.py b/portas/portas/common/config.py index c0ea7d0..58a6378 100644 --- a/portas/portas/common/config.py +++ b/portas/portas/common/config.py @@ -82,6 +82,7 @@ def parse_args(args=None, usage=None, default_config_files=None): usage=usage, default_config_files=default_config_files) + def setup_logging(): """ Sets up the logging options for a log with supplied name diff --git a/portas/portas/common/exception.py b/portas/portas/common/exception.py index 59bb0ee..7f338e8 100644 --- a/portas/portas/common/exception.py +++ b/portas/portas/common/exception.py @@ -45,6 +45,7 @@ class PortasException(Exception): super(PortasException, self).__init__(message) + class SchemaLoadError(PortasException): message = _("Unable to load schema: %(reason)s") @@ -52,5 +53,3 @@ class SchemaLoadError(PortasException): class InvalidObject(PortasException): message = _("Provided object does not match schema " "'%(schema)s': %(reason)s") - - diff --git a/portas/portas/common/service.py b/portas/portas/common/service.py index 143a358..2d8f38e 100644 --- a/portas/portas/common/service.py +++ b/portas/portas/common/service.py @@ -27,14 +27,18 @@ class TaskResultHandlerService(service.Service): super(TaskResultHandlerService, self).stop() def _handle_results(self): - connection = amqp.Connection('{0}:{1}'.format(rabbitmq.host, rabbitmq.port), virtual_host=rabbitmq.virtual_host, - userid=rabbitmq.userid, password=rabbitmq.password, + connection = amqp.Connection('{0}:{1}'. + format(rabbitmq.host, rabbitmq.port), + virtual_host=rabbitmq.virtual_host, + userid=rabbitmq.userid, + password=rabbitmq.password, ssl=rabbitmq.use_ssl, insist=True) ch = connection.channel() def bind(exchange, queue): if not exchange: - ch.exchange_declare(exchange, 'direct', durable=True, auto_delete=False) + ch.exchange_declare(exchange, 'direct', durable=True, + auto_delete=False) ch.queue_declare(queue, durable=True, auto_delete=False) if not exchange: ch.queue_bind(queue, exchange, queue) @@ -43,13 +47,15 @@ class TaskResultHandlerService(service.Service): bind(conf.reports_exchange, conf.reports_queue) ch.basic_consume(conf.results_exchange, callback=handle_result) - ch.basic_consume(conf.reports_exchange, callback=handle_report, no_ack=True) + ch.basic_consume(conf.reports_exchange, callback=handle_report, + no_ack=True) while ch.callbacks: ch.wait() def handle_report(msg): - log.debug(_('Got report message from orchestration engine:\n{0}'.format(msg.body))) + log.debug(_('Got report message from orchestration engine:\n{0}'. + format(msg.body))) params = anyjson.deserialize(msg.body) params['entity_id'] = params['id'] @@ -61,7 +67,8 @@ def handle_report(msg): session = get_session() #connect with session conf_session = session.query(Session).filter_by( - **{'environment_id': status.environment_id, 'state': 'deploying'}).first() + **{'environment_id': status.environment_id, + 'state': 'deploying'}).first() status.session_id = conf_session.id with session.begin(): @@ -69,7 +76,8 @@ def handle_report(msg): def handle_result(msg): - log.debug(_('Got result message from orchestration engine:\n{0}'.format(msg.body))) + log.debug(_('Got result message from orchestration engine:\n{0}'. + format(msg.body))) environment_result = anyjson.deserialize(msg.body) diff --git a/portas/portas/common/uuidutils.py b/portas/portas/common/uuidutils.py index f3513ac..cf00651 100644 --- a/portas/portas/common/uuidutils.py +++ b/portas/portas/common/uuidutils.py @@ -2,4 +2,4 @@ import uuid def generate_uuid(): - return str(uuid.uuid4()).replace('-', '') \ No newline at end of file + return str(uuid.uuid4()).replace('-', '') diff --git a/portas/portas/context.py b/portas/portas/context.py index 9fb9c56..c541829 100644 --- a/portas/portas/context.py +++ b/portas/portas/context.py @@ -24,7 +24,9 @@ class RequestContext(object): accesses the system, as well as additional request information. """ - def __init__(self, auth_tok=None, user=None, tenant=None, roles=None, service_catalog=None, session=None): + def __init__(self, auth_tok=None, user=None, tenant=None, + roles=None, service_catalog=None, session=None): + self.auth_tok = auth_tok self.user = user self.tenant = tenant @@ -55,4 +57,4 @@ class RequestContext(object): @classmethod def from_dict(cls, values): - return cls(**values) \ No newline at end of file + return cls(**values) diff --git a/portas/portas/db/__init__.py b/portas/portas/db/__init__.py index 75fd934..2070644 100644 --- a/portas/portas/db/__init__.py +++ b/portas/portas/db/__init__.py @@ -9,4 +9,4 @@ sql_connection_opt = cfg.StrOpt('sql_connection', 'Default: %(default)s') CONF = cfg.CONF -CONF.register_opt(sql_connection_opt) \ No newline at end of file +CONF.register_opt(sql_connection_opt) diff --git a/portas/portas/db/migrate_repo/versions/001_add_initial_tables.py b/portas/portas/db/migrate_repo/versions/001_add_initial_tables.py index f2262f2..52a6d16 100644 --- a/portas/portas/db/migrate_repo/versions/001_add_initial_tables.py +++ b/portas/portas/db/migrate_repo/versions/001_add_initial_tables.py @@ -11,7 +11,7 @@ Table('environment', meta, Column('updated', DateTime(), nullable=False), Column('tenant_id', String(32), nullable=False), Column('description', Text(), nullable=False), -) + ) Table('service', meta, Column('id', String(32), primary_key=True), @@ -21,7 +21,7 @@ Table('service', meta, Column('created', DateTime, nullable=False), Column('updated', DateTime, nullable=False), Column('description', Text(), nullable=False), -) + ) def upgrade(migrate_engine): diff --git a/portas/portas/db/migrate_repo/versions/002_add_session_table.py b/portas/portas/db/migrate_repo/versions/002_add_session_table.py index d9ca59c..30f89c8 100644 --- a/portas/portas/db/migrate_repo/versions/002_add_session_table.py +++ b/portas/portas/db/migrate_repo/versions/002_add_session_table.py @@ -5,12 +5,13 @@ meta = MetaData() session = Table('session', meta, Column('id', String(32), primary_key=True), - Column('environment_id', String(32), ForeignKey('environment.id')), + Column('environment_id', String(32), + ForeignKey('environment.id')), Column('created', DateTime, nullable=False), Column('updated', DateTime, nullable=False), Column('user_id', String(32), nullable=False), Column('state', Text(), nullable=False), -) + ) def upgrade(migrate_engine): diff --git a/portas/portas/db/migrate_repo/versions/003_add_status_table.py b/portas/portas/db/migrate_repo/versions/003_add_status_table.py index 6bacb9c..1ee86b2 100644 --- a/portas/portas/db/migrate_repo/versions/003_add_status_table.py +++ b/portas/portas/db/migrate_repo/versions/003_add_status_table.py @@ -8,10 +8,11 @@ status = Table('status', meta, Column('created', DateTime, nullable=False), Column('updated', DateTime, nullable=False), Column('entity', String(10), nullable=False), - Column('environment_id', String(32), ForeignKey('environment.id')), + Column('environment_id', String(32), + ForeignKey('environment.id')), Column('session_id', String(32), ForeignKey('session.id')), Column('text', Text(), nullable=False), -) + ) def upgrade(migrate_engine): diff --git a/portas/portas/db/migrate_repo/versions/005_remove_obsolete_service_table.py b/portas/portas/db/migrate_repo/versions/005_remove_obsolete_service_table.py index 2692829..8c3bfc1 100644 --- a/portas/portas/db/migrate_repo/versions/005_remove_obsolete_service_table.py +++ b/portas/portas/db/migrate_repo/versions/005_remove_obsolete_service_table.py @@ -5,14 +5,15 @@ from sqlalchemy.types import String, Text, DateTime meta = MetaData() service = Table('service', meta, - Column('id', String(32), primary_key=True), - Column('name', String(255), nullable=False), - Column('type', String(40), nullable=False), - Column('environment_id', String(32), ForeignKey('environment.id')), - Column('created', DateTime, nullable=False), - Column('updated', DateTime, nullable=False), - Column('description', Text(), nullable=False), -) + Column('id', String(32), primary_key=True), + Column('name', String(255), nullable=False), + Column('type', String(40), nullable=False), + Column('environment_id', String(32), + ForeignKey('environment.id')), + Column('created', DateTime, nullable=False), + Column('updated', DateTime, nullable=False), + Column('description', Text(), nullable=False), + ) def upgrade(migrate_engine): diff --git a/portas/portas/db/models.py b/portas/portas/db/models.py index 412d1fb..9491bab 100644 --- a/portas/portas/db/models.py +++ b/portas/portas/db/models.py @@ -83,7 +83,8 @@ class ModelBase(object): def to_dict(self): dictionary = self.__dict__.copy() - return {k: v for k, v in dictionary.iteritems() if k != '_sa_instance_state'} + return {k: v for k, v in dictionary.iteritems() + if k != '_sa_instance_state'} class JsonBlob(TypeDecorator): diff --git a/portas/portas/utils.py b/portas/portas/utils.py index 393c6fb..30ae919 100644 --- a/portas/portas/utils.py +++ b/portas/portas/utils.py @@ -11,8 +11,8 @@ def verify_session(func): @functools.wraps(func) def __inner(self, request, *args, **kwargs): if hasattr(request, 'context') and request.context.session: - uw = get_session() - configuration_session = uw.query(Session).get(request.context.session) + uw = get_session().query(Session) + configuration_session = uw.get(request.context.session) if configuration_session.state != 'open': log.info('Session is already deployed') @@ -22,5 +22,3 @@ def verify_session(func): raise exc.HTTPUnauthorized return func(self, request, *args, **kwargs) return __inner - - diff --git a/python-portasclient/portasclient/version.py b/python-portasclient/portasclient/version.py index 53823b3..c140d8d 100644 --- a/python-portasclient/portasclient/version.py +++ b/python-portasclient/portasclient/version.py @@ -15,6 +15,6 @@ # under the License. -from portas.openstack.common import version as common_version +from portasclient.openstack.common import version as common_version version_info = common_version.VersionInfo('python-portasclient') diff --git a/python-portasclient/tests/test_sanity.py b/python-portasclient/tests/test_sanity.py index 89d3628..87da75d 100644 --- a/python-portasclient/tests/test_sanity.py +++ b/python-portasclient/tests/test_sanity.py @@ -1,19 +1,29 @@ +import os import unittest import logging from mock import MagicMock +from mock import patch +from portasclient.client import Client as CommonClient from portasclient.v1 import Client import portasclient.v1.environments as environments import portasclient.v1.services as services import portasclient.v1.sessions as sessions +import portasclient.shell as shell +import portasclient.common.http as http + + LOG = logging.getLogger('Unit tests') + def my_mock(*a, **b): return [a, b] + api = MagicMock(json_request=my_mock) + class SanityUnitTests(unittest.TestCase): def test_create_client_instance(self): @@ -25,145 +35,121 @@ class SanityUnitTests(unittest.TestCase): assert test_client.sessions is not None assert test_client.activeDirectories is not None assert test_client.webServers is not None + + def test_common_client(self): + endpoint = 'http://localhost:8001' + test_client = CommonClient('1', endpoint=endpoint, token='1', timeout=10) + + assert test_client.environments is not None + assert test_client.sessions is not None + assert test_client.activeDirectories is not None + assert test_client.webServers is not None def test_env_manager_list(self): - manager = environments.EnvironmentManager(api) - result = manager.list() - assert result == [] def test_env_manager_create(self): - manager = environments.EnvironmentManager(api) - result = manager.create('test') - assert result.headers == {} assert result.body == {'name': 'test'} def test_env_manager_delete(self): - manager = environments.EnvironmentManager(api) - result = manager.delete('test') - assert result is None def test_env_manager_update(self): - manager = environments.EnvironmentManager(api) - result = manager.update('1', 'test') - assert result.body == {'name': 'test'} def test_env_manager_get(self): - manager = environments.EnvironmentManager(api) - result = manager.get('test') ## WTF? assert result.manager is not None + + def test_env(self): + environment = environments.Environment(api, api) + assert environment.data() is not None def test_ad_manager_list(self): - manager = services.ActiveDirectoryManager(api) - result = manager.list('datacenter1') - + assert result == [] + result = manager.list('datacenter1', '1') assert result == [] def test_ad_manager_create(self): - manager = services.ActiveDirectoryManager(api) - result = manager.create('datacenter1', 'session1', 'test') - assert result.headers == {'X-Configuration-Session': 'session1'} assert result.body == 'test' #@unittest.skip("https://mirantis.jira.com/browse/KEERO-218") def test_ad_manager_delete(self): - manager = services.ActiveDirectoryManager(api) - result = manager.delete('datacenter1', 'session1', 'test') - assert result is None def test_iis_manager_list(self): - manager = services.WebServerManager(api) - result = manager.list('datacenter1') - + assert result == [] + result = manager.list('datacenter1', '1') assert result == [] def test_iis_manager_create(self): - manager = services.WebServerManager(api) - result = manager.create('datacenter1', 'session1', 'test') - assert result.headers == {'X-Configuration-Session': 'session1'} assert result.body == 'test' #@unittest.skip("https://mirantis.jira.com/browse/KEERO-218") def test_iis_manager_delete(self): - manager = services.WebServerManager(api) - result = manager.delete('datacenter1', 'session1', 'test') - assert result is None + def test_service_ad(self): + service_ad = services.ActiveDirectory(api, api) + assert service_ad.data() is not None + + def test_service_iis(self): + service_iis = services.ActiveDirectory(api, api) + assert service_iis.data() is not None + def test_session_manager_list(self): - manager = sessions.SessionManager(api) - result = manager.list('datacenter1') - assert result == [] def test_session_manager_delete(self): - manager = sessions.SessionManager(api) - result = manager.delete('datacenter1', 'session1') - assert result is None def test_session_manager_get(self): - manager = sessions.SessionManager(api) - result = manager.get('datacenter1', 'session1') # WTF? assert result.manager is not None def test_session_manager_configure(self): - manager = sessions.SessionManager(api) - result = manager.configure('datacenter1') - assert result.headers == {} def test_session_manager_deploy(self): - manager = sessions.SessionManager(api) - result = manager.deploy('datacenter1', '1') - assert result is None #@unittest.skip("https://mirantis.jira.com/browse/KEERO-219") def test_session_manager_reports(self): - manager = sessions.SessionManager(api) - result = manager.reports('datacenter1', '1') - assert result == [] \ No newline at end of file From 29da07cda8e456a7ffa678c1b28ae3f1a800a116 Mon Sep 17 00:00:00 2001 From: Timur Nurlygayanov Date: Tue, 26 Mar 2013 06:36:57 +0700 Subject: [PATCH 09/14] Added initial unit tests for RestAPI service. --- portas/portas/tests/sanity_tests.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 portas/portas/tests/sanity_tests.py diff --git a/portas/portas/tests/sanity_tests.py b/portas/portas/tests/sanity_tests.py new file mode 100644 index 0000000..d6258f2 --- /dev/null +++ b/portas/portas/tests/sanity_tests.py @@ -0,0 +1,24 @@ +import unittest2 +from mock import MagicMock + +import portas.api.v1.router as router + +def my_mock(link, controller, action, conditions): + return [link, controller, action, conditions] + +def func_mock(): + return True + +class SanityUnitTests(unittest2.TestCase): + + def test_api(self): + router.webservers = MagicMock(create_resource=func_mock) + router.sessions = MagicMock(create_resource=func_mock) + router.active_directories = MagicMock(create_resource=func_mock) + router.environments = MagicMock(create_resource=func_mock) + mapper = MagicMock(connect=my_mock) + + object = router.API(mapper) + + assert object._router is not None + \ No newline at end of file From b59edd7ad2d242bb1c011e833e4e872ee5e8d1dc Mon Sep 17 00:00:00 2001 From: Serg Melikyan Date: Tue, 26 Mar 2013 12:34:22 +0400 Subject: [PATCH 10/14] #KEERO-220 Send X-Auth-Token to Conductor --- portas/portas/api/v1/sessions.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/portas/portas/api/v1/sessions.py b/portas/portas/api/v1/sessions.py index 5bf52b0..b1584d0 100644 --- a/portas/portas/api/v1/sessions.py +++ b/portas/portas/api/v1/sessions.py @@ -121,9 +121,13 @@ class Controller(object): session.state = 'deploying' session.save(unit) + #Set X-Auth-Tokenconductor for conductor + env = session.description + env['token'] = request.context.auth_token + with self.write_lock: self.ch.basic_publish(Message(body=anyjson. - serialize(session.description)), + serialize(env)), 'tasks', 'tasks') From e4abc9b157bce2741024c0225778ca2575de50c9 Mon Sep 17 00:00:00 2001 From: Timur Nurlygayanov Date: Tue, 26 Mar 2013 13:24:37 +0400 Subject: [PATCH 11/14] Fixed WebUI tests. Added new tests. --- tests/selenium/datacenters_page.py | 30 +++++-- tests/selenium/page.py | 85 ++++++++++++++---- tests/selenium/services_page.py | 11 ++- tests/selenium/test.py | 135 +++++++++++++++++++++++++---- 4 files changed, 214 insertions(+), 47 deletions(-) diff --git a/tests/selenium/datacenters_page.py b/tests/selenium/datacenters_page.py index f0e74a8..03e4e26 100644 --- a/tests/selenium/datacenters_page.py +++ b/tests/selenium/datacenters_page.py @@ -4,9 +4,9 @@ import page class DataCentersPage(page.Page): - page = None def create_data_center(self, name): + self.Refresh() self.Button('Create Windows Data Center').Click() @@ -14,14 +14,12 @@ class DataCentersPage(page.Page): xpath = "//input[@value='Create']" self.Button(xpath).Click() - return self - def delete_data_center(self, name): + self.Refresh() + link = self.Link(name).Address() datacenter_id = re.search('windc/(\S+)', link).group(0)[6:-1] - print 'Data Center ID: ' + datacenter_id - xpath = ".//*[@id='windc__row__%s']/td[4]/div/a[2]" % datacenter_id self.Button(xpath).Click() @@ -30,9 +28,27 @@ class DataCentersPage(page.Page): self.Button("Delete Data Center").Click() - return self - def select_data_center(self, name): self.Link(name).Click() page = ServicesPage(self.driver) return page + + def deploy_data_center(self, name): + self.Refresh() + + link = self.Link(name).Address() + datacenter_id = re.search('windc/(\S+)', link).group(0)[6:-1] + + xpath = ".//*[@id='windc__row__%s']/td[4]/div/a[2]" % datacenter_id + self.Button(xpath).Click() + + button_id = "windc__row_%s__action_deploy" % datacenter_id + self.Button(button_id).Click() + + def get_datacenter_status(self, name): + self.Navigate('Windows Data Centers') + link = self.Link(name).Address() + datacenter_id = re.search('windc/(\S+)', link).group(0)[6:-1] + + xpath = ".//*[@id='windc__row__%s']/td[3]" % datacenter_id + return self.TableCell(xpath).Text() diff --git a/tests/selenium/page.py b/tests/selenium/page.py index 80085ab..43ed7cc 100644 --- a/tests/selenium/page.py +++ b/tests/selenium/page.py @@ -1,16 +1,38 @@ +import logging +from selenium.webdriver.support.ui import Select +logging.basicConfig() +LOG = logging.getLogger(' Page object: ') + + +class TableCellClass: + table = None + + def __init__(self, obj): + if not obj: + LOG.error('TableCell does not found') + self.table = obj + + def Text(self): + if self.table: + return self.table.text() + else: + return '' class ButtonClass: button = None def __init__(self, obj): + if not obj: + LOG.error('Button does not found') self.button = obj def Click(self): - self.button.click() + if self.button: + self.button.click() def isPresented(self): - if self.button != None: + if self.button: return True return False @@ -19,60 +41,84 @@ class LinkClass: link = None def __init__(self, obj): + if not obj: + LOG.error('Link does not found') self.link = obj def Click(self): - self.link.click() + if self.link: + self.link.click() def isPresented(self): - if self.link != None: + if self.link: return True return False def Address(self): - return self.link.get_attribute('href') + if self.link: + return self.link.get_attribute('href') + else: + return '' class EditBoxClass: def __init__(self, obj): + if not obj: + LOG.error('EditBox does not found') self.edit = obj def isPresented(self): - if self.edit != None: + if self.edit: return True return False def Set(self, value): - self.edit.clear() - self.edit.send_keys(value) + if self.edit: + self.edit.clear() + self.edit.send_keys(value) def Text(self): - return self.edit.get_text() + if self.edit: + return self.edit.get_text() + else: + return '' class DropDownListClass: select = None def __init__(self, obj): + if not obj: + LOG.error('DropDownList does not found') self.select = obj def isPresented(self): - if self.select != None: + if self.select is not None: return True return False def Set(self, value): - self.select.select_by_visible_text(value) + if self.select: + Select(self.select).select_by_visible_text(value) def Text(self): - return self.select.get_text() + if self.select: + return self.select.get_text() + else: + return '' + + +error_msg = """ + Object with parameter: %s + does not found on page. + """ class Page: driver = None - timeout = 300 + timeout = 30 def __init__(self, driver): driver.set_page_load_timeout(30) @@ -82,7 +128,7 @@ class Page: def _find_element(self, parameter): obj = None k = 0 - while (obj == None and k < self.timeout): + while (obj is None and k < self.timeout): k += 1 try: obj = self.driver.find_element_by_name(parameter) @@ -105,11 +151,20 @@ class Page: except: pass - return obj + LOG.error(error_msg % parameter) + return None def Open(self, url): self.driver.get(url) + def Refresh(self): + self.driver.refresh() + + def TableCell(self, name): + obj = self._find_element(name) + table = TableCellClass(obj) + return table + def Button(self, name): obj = self._find_element(name) button = ButtonClass(obj) diff --git a/tests/selenium/services_page.py b/tests/selenium/services_page.py index e8ea9f8..772b9df 100644 --- a/tests/selenium/services_page.py +++ b/tests/selenium/services_page.py @@ -5,19 +5,20 @@ import re class ServicesPage(page.Page): def create_service(self, service_type, parameters): + self.Refresh() self.Button('services__action_CreateService').Click() self.DropDownList('0-service').Set(service_type) self.Button('wizard_goto_step').Click() - for parameter in parameters: - self.EditBox(parameter.key).Set(parameter.value) + for key in parameters: + self.EditBox(key).Set(parameters[key]) self.Button("//input[@value='Create']").Click() - return self - def delete_service(self, name): + self.Refresh() + link = self.Link(name).Address() service_id = re.search('windc/(\S+)', link).group(0)[6:-1] @@ -29,5 +30,3 @@ class ServicesPage(page.Page): self.Button(button_id).Click() self.Button("Delete Service").Click() - - return self diff --git a/tests/selenium/test.py b/tests/selenium/test.py index 4391a0b..1af0699 100644 --- a/tests/selenium/test.py +++ b/tests/selenium/test.py @@ -5,19 +5,7 @@ from login_page import LoginPage from datacenters_page import DataCentersPage from selenium import webdriver - -class SanityTests(unittest2.TestCase): - - def setUp(self): - driver = webdriver.Firefox() - self.page = LoginPage(driver) - self.page.login() - self.page.Navigate('Project:Windows Data Centers') - self.page = DataCentersPage(driver) - - def tearDown(self): - self.page.driver.close() - +""" def test_01_create_data_center(self): self.page.create_data_center('dc1') assert self.page.Link('dc1').isPresented() @@ -27,25 +15,42 @@ class SanityTests(unittest2.TestCase): assert not self.page.Link('dc1').isPresented() def test_03_create_data_centers(self): - for i in range(1, 20): + for i in range(1, 10): name = 'datacenter' + str(i) self.page.create_data_center(name) assert self.page.Link(name).isPresented() def test_04_delete_data_centers(self): self.page.delete_data_center('datacenter1') - self.page.delete_data_center('datacenter20') + self.page.delete_data_center('datacenter9') assert not self.page.Link('datacenter1').isPresented() - assert not self.page.Link('datacenter20').isPresented() + assert not self.page.Link('datacenter9').isPresented() - for i in range(2, 19): + for i in range(2, 9): name = 'datacenter' + str(i) assert self.page.Link(name).isPresented() +""" + + +class SanityTests(unittest2.TestCase): + + @classmethod + def setUpClass(self): + driver = webdriver.Firefox() + self.page = LoginPage(driver) + self.page.login() + self.page.Navigate('Project:Windows Data Centers') + self.page = DataCentersPage(driver) + + @classmethod + def tearDownClass(self): + self.page.driver.close() def test_05_create_service_ad(self): name = 'dc001.local' - self.page.create_data_center('test') - self.page.select_data_center('test') + self.page.Navigate('Windows Data Centers') + self.page.create_data_center('test05') + self.page = self.page.select_data_center('test05') ad_parameters = {'1-dc_name': name, '1-dc_count': 1, @@ -54,7 +59,99 @@ class SanityTests(unittest2.TestCase): self.page.create_service('Active Directory', ad_parameters) assert self.page.Link(name).isPresented() +""" + def test_06_create_service_ad_two_instances(self): + name = 'dc002.local' + self.page.Navigate('Windows Data Centers') + self.page.create_data_center('test06') + self.page = self.page.select_data_center('test06') + ad_parameters = {'1-dc_name': name, + '1-dc_count': 2, + '1-adm_password': 'P@ssw0rd2', + '1-recovery_password': 'P@ssw0rd'} + self.page.create_service('Active Directory', ad_parameters) + + assert self.page.Link(name).isPresented() + + def test_07_create_service_ad_with_iis(self): + ad_name = 'dc003.local' + self.page.Navigate('Windows Data Centers') + self.page.create_data_center('test07') + self.page = self.page.select_data_center('test07') + + ad_parameters = {'1-dc_name': ad_name, + '1-dc_count': 3, + '1-adm_password': 'P@ssw0rd', + '1-recovery_password': 'P@ssw0rd2'} + self.page.create_service('Active Directory', ad_parameters) + + assert self.page.Link(ad_name).isPresented() + + iis_name = 'iis_server1' + iis_parameters = {'1-iis_name': iis_name, + '1-adm_password': 'P@ssw0rd', + '1-iis_domain': 'dc003.local', + '1-domain_user_name': 'Administrator', + '1-domain_user_password': 'P@ssw0rd'} + self.page.create_service('Internet Information Services', + iis_parameters) + + assert self.page.Link(iis_name).isPresented() + + iis_name = 'iis_server2' + iis_parameters = {'1-iis_name': iis_name, + '1-adm_password': 'P@ssw0rd', + '1-iis_domain': 'dc003.local', + '1-domain_user_name': 'Administrator', + '1-domain_user_password': 'P@ssw0rd'} + self.page.create_service('Internet Information Services', + iis_parameters) + + assert self.page.Link(iis_name).isPresented() + + iis_name = 'iis_server3' + iis_parameters = {'1-iis_name': iis_name, + '1-adm_password': 'P@ssw0rd', + '1-iis_domain': 'dc003.local', + '1-domain_user_name': 'Administrator', + '1-domain_user_password': 'P@ssw0rd'} + self.page.create_service('Internet Information Services', + iis_parameters) + + assert self.page.Link(iis_name).isPresented() + + def test_08_deploy_data_center(self): + ad_name = 'AD.net' + self.page.Navigate('Windows Data Centers') + self.page.create_data_center('test08') + self.page = self.page.select_data_center('test08') + + ad_parameters = {'1-dc_name': ad_name, + '1-dc_count': 2, + '1-adm_password': 'P@ssw0rd', + '1-recovery_password': 'P@ssw0rd2'} + self.page.create_service('Active Directory', ad_parameters) + + assert self.page.Link(ad_name).isPresented() + + iis_parameters = {'1-iis_name': 'iis_server', + '1-adm_password': 'P@ssw0rd', + '1-iis_domain': 'AD.net', + '1-domain_user_name': 'Administrator', + '1-domain_user_password': 'P@ssw0rd'} + self.page.create_service('Internet Information Services', + iis_parameters) + + assert self.page.Link('iis_server').isPresented() + + self.page.Navigate('Windows Data Centers') + self.page = DataCentersPage(self.page.driver) + self.page.deploy_data_center('test08') + + status = self.page.get_datacenter_status('test08') + assert 'Deploy in progress' in status +""" if __name__ == '__main__': unittest2.main() From ccd0a3c904a09267e7065228561a628c0cdf35d2 Mon Sep 17 00:00:00 2001 From: Timur Nurlygayanov Date: Tue, 26 Mar 2013 13:29:50 +0400 Subject: [PATCH 12/14] Hot fix for WebUI tests. --- tests/selenium/test.py | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/tests/selenium/test.py b/tests/selenium/test.py index 1af0699..b1c2b60 100644 --- a/tests/selenium/test.py +++ b/tests/selenium/test.py @@ -5,7 +5,21 @@ from login_page import LoginPage from datacenters_page import DataCentersPage from selenium import webdriver -""" + +class SanityTests(unittest2.TestCase): + + @classmethod + def setUpClass(self): + driver = webdriver.Firefox() + self.page = LoginPage(driver) + self.page.login() + self.page.Navigate('Project:Windows Data Centers') + self.page = DataCentersPage(driver) + + @classmethod + def tearDownClass(self): + self.page.driver.close() + def test_01_create_data_center(self): self.page.create_data_center('dc1') assert self.page.Link('dc1').isPresented() @@ -29,22 +43,6 @@ from selenium import webdriver for i in range(2, 9): name = 'datacenter' + str(i) assert self.page.Link(name).isPresented() -""" - - -class SanityTests(unittest2.TestCase): - - @classmethod - def setUpClass(self): - driver = webdriver.Firefox() - self.page = LoginPage(driver) - self.page.login() - self.page.Navigate('Project:Windows Data Centers') - self.page = DataCentersPage(driver) - - @classmethod - def tearDownClass(self): - self.page.driver.close() def test_05_create_service_ad(self): name = 'dc001.local' @@ -59,7 +57,7 @@ class SanityTests(unittest2.TestCase): self.page.create_service('Active Directory', ad_parameters) assert self.page.Link(name).isPresented() -""" + def test_06_create_service_ad_two_instances(self): name = 'dc002.local' self.page.Navigate('Windows Data Centers') @@ -151,7 +149,7 @@ class SanityTests(unittest2.TestCase): status = self.page.get_datacenter_status('test08') assert 'Deploy in progress' in status -""" + if __name__ == '__main__': unittest2.main() From a0069520804b0ef863dee4419ce42a48cfee898e Mon Sep 17 00:00:00 2001 From: Serg Melikyan Date: Tue, 26 Mar 2013 13:36:05 +0400 Subject: [PATCH 13/14] Send Env to Conductor for deletion --- portas/portas/api/v1/environments.py | 24 +++++++++++++++++++++ portas/portas/api/v1/sessions.py | 31 ++++++++++++---------------- portas/portas/common/service.py | 12 ++++++++--- 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/portas/portas/api/v1/environments.py b/portas/portas/api/v1/environments.py index 4129bbf..5e85fa7 100644 --- a/portas/portas/api/v1/environments.py +++ b/portas/portas/api/v1/environments.py @@ -1,10 +1,16 @@ +from amqplib.client_0_8 import Message +import anyjson +import eventlet from webob import exc +from portas.common import config from portas.api.v1 import get_env_status from portas.db.session import get_session from portas.db.models import Environment from portas.openstack.common import wsgi from portas.openstack.common import log as logging +amqp = eventlet.patcher.import_patched('amqplib.client_0_8') +rabbitmq = config.CONF.rabbitmq log = logging.getLogger(__name__) @@ -85,6 +91,24 @@ class Controller(object): with session.begin(): session.delete(environment) + #preparing data for removal from conductor + env = environment.description + env['services'] = [] + env['deleted'] = True + + connection = amqp.Connection('{0}:{1}'. + format(rabbitmq.host, rabbitmq.port), + virtual_host=rabbitmq.virtual_host, + userid=rabbitmq.userid, + password=rabbitmq.password, + ssl=rabbitmq.use_ssl, insist=True) + channel = connection.channel() + channel.exchange_declare('tasks', 'direct', durable=True, + auto_delete=False) + + channel.basic_publish(Message(body=anyjson.serialize(env)), 'tasks', + 'tasks') + return None diff --git a/portas/portas/api/v1/sessions.py b/portas/portas/api/v1/sessions.py index b1584d0..5fb30c0 100644 --- a/portas/portas/api/v1/sessions.py +++ b/portas/portas/api/v1/sessions.py @@ -1,7 +1,6 @@ from amqplib.client_0_8 import Message import anyjson import eventlet -from eventlet.semaphore import Semaphore from webob import exc from portas.common import config from portas.db.models import Session, Status, Environment @@ -15,18 +14,6 @@ log = logging.getLogger(__name__) class Controller(object): - def __init__(self): - self.write_lock = Semaphore(1) - connection = amqp.Connection('{0}:{1}'. - format(rabbitmq.host, rabbitmq.port), - virtual_host=rabbitmq.virtual_host, - userid=rabbitmq.userid, - password=rabbitmq.password, - ssl=rabbitmq.use_ssl, insist=True) - self.ch = connection.channel() - self.ch.exchange_declare('tasks', 'direct', durable=True, - auto_delete=False) - def index(self, request, environment_id): log.debug(_('Session:List '.format(environment_id))) @@ -121,14 +108,22 @@ class Controller(object): session.state = 'deploying' session.save(unit) - #Set X-Auth-Tokenconductor for conductor + #Set X-Auth-Token for conductor env = session.description env['token'] = request.context.auth_token - with self.write_lock: - self.ch.basic_publish(Message(body=anyjson. - serialize(env)), - 'tasks', 'tasks') + connection = amqp.Connection('{0}:{1}'. + format(rabbitmq.host, rabbitmq.port), + virtual_host=rabbitmq.virtual_host, + userid=rabbitmq.userid, + password=rabbitmq.password, + ssl=rabbitmq.use_ssl, insist=True) + channel = connection.channel() + channel.exchange_declare('tasks', 'direct', durable=True, + auto_delete=False) + + channel.basic_publish(Message(body=anyjson.serialize(env)), 'tasks', + 'tasks') def create_resource(): diff --git a/portas/portas/common/service.py b/portas/portas/common/service.py index 2d8f38e..238304e 100644 --- a/portas/portas/common/service.py +++ b/portas/portas/common/service.py @@ -55,7 +55,7 @@ class TaskResultHandlerService(service.Service): def handle_report(msg): log.debug(_('Got report message from orchestration engine:\n{0}'. - format(msg.body))) + format(msg.body))) params = anyjson.deserialize(msg.body) params['entity_id'] = params['id'] @@ -76,10 +76,16 @@ def handle_report(msg): def handle_result(msg): - log.debug(_('Got result message from orchestration engine:\n{0}'. - format(msg.body))) + log.debug(_('Got result message from ' + 'orchestration engine:\n{0}'.format(msg.body))) environment_result = anyjson.deserialize(msg.body) + if environment_result['deleted']: + log.debug(_('Result for environment {0} is dropped. ' + 'Environment is deleted'.format(environment_result['id']))) + + msg.channel.basic_ack(msg.delivery_tag) + return session = get_session() environment = session.query(Environment).get(environment_result['id']) From fe143e4675669ed4ef519df5ef7bf7045b1fce89 Mon Sep 17 00:00:00 2001 From: Serg Melikyan Date: Tue, 26 Mar 2013 13:46:29 +0400 Subject: [PATCH 14/14] #KEERO-222 Remove random part of unit name --- portas/portas/api/v1/active_directories.py | 3 +-- portas/portas/api/v1/webservers.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/portas/portas/api/v1/active_directories.py b/portas/portas/api/v1/active_directories.py index bacdb2a..ade7a6f 100644 --- a/portas/portas/api/v1/active_directories.py +++ b/portas/portas/api/v1/active_directories.py @@ -38,8 +38,7 @@ class Controller(object): for unit in active_directory['units']: unit_count += 1 unit['id'] = uuidutils.generate_uuid() - unit['name'] = 'dc{0}{1}'.format(unit_count, - active_directory['id'][:4]) + unit['name'] = 'dc{0}'.format(unit_count) draft = prepare_draft(draft) draft['services']['activeDirectories'].append(active_directory) diff --git a/portas/portas/api/v1/webservers.py b/portas/portas/api/v1/webservers.py index ef1344f..ddc73c3 100644 --- a/portas/portas/api/v1/webservers.py +++ b/portas/portas/api/v1/webservers.py @@ -36,7 +36,7 @@ class Controller(object): for unit in webServer['units']: unit_count += 1 unit['id'] = uuidutils.generate_uuid() - unit['name'] = 'iis{0}{1}'.format(unit_count, webServer['id'][:3]) + unit['name'] = 'iis{0}'.format(unit_count) draft = prepare_draft(draft) draft['services']['webServers'].append(webServer)