From f68a00bfa9cd264bf9c45b3e9a646cb995dc35ff Mon Sep 17 00:00:00 2001 From: Nikolay Markov Date: Wed, 11 Jul 2012 16:44:22 +0400 Subject: [PATCH] new ssh client and install_cookbook missing recipes fix --- bin/install_cookbook | 4 ++ test/integration/__init__.py | 8 +++ test/integration/helpers.py | 91 +++++++++++++++-------------------- test/integration/test_node.py | 86 +++++++++++++++++++-------------- 4 files changed, 102 insertions(+), 87 deletions(-) diff --git a/bin/install_cookbook b/bin/install_cookbook index a2c705a05..6445085f4 100755 --- a/bin/install_cookbook +++ b/bin/install_cookbook @@ -47,6 +47,10 @@ def create_recipes(metafile, md, attr_id) cook_name = md.name.empty? ? File.basename(File.dirname(metafile)) : md.name recipes_dir = File.join(File.dirname(metafile), "recipes") + unless File.exists?(recipes_dir) and File.readable?(recipes_dir) + puts "Recipes folder not found." + return true + end Dir.chdir(recipes_dir) recipes = Dir.glob("*.rb") diff --git a/test/integration/__init__.py b/test/integration/__init__.py index c9fb523c3..38b870b9d 100644 --- a/test/integration/__init__.py +++ b/test/integration/__init__.py @@ -53,6 +53,14 @@ class Ci(object): node.cdrom = Cdrom(isopath=self.iso) node.boot = ['disk', 'cdrom'] environment.nodes.append(node) + + node2 = Node('slave') + node2.memory = 2048 + node2.vnc = True + node2.disks.append(Disk(size=30*1024**3)) + node2.interfaces.append(Interface(network)) + node2.boot = ['network'] + environment.nodes.append(node2) devops.build(environment) except Exception, e: diff --git a/test/integration/helpers.py b/test/integration/helpers.py index 81b108c35..aa06b9399 100644 --- a/test/integration/helpers.py +++ b/test/integration/helpers.py @@ -41,10 +41,20 @@ class HTTPClient(object): class SSHClient(object): + class get_sudo(object): + def __init__(self, client): + self.client = client + + def __enter__(self): + self.client.sudo_mode = True + + def __exit__(self, type, value, traceback): + self.client.sudo_mode = False def __init__(self): self.channel = None - self.sudo = False + self.sudo_mode = False + self.sudo = self.get_sudo(self) def connect_ssh(self, host, username, password): self.ssh_client = paramiko.SSHClient() @@ -55,53 +65,39 @@ class SSHClient(object): self.ssh_client.connect(host, username=username, password=password) self.sftp_client = self.ssh_client.open_sftp() - def open_channel(self): - if not self.channel: - self.channel = self.ssh_client.invoke_shell() - def aquire_sudo(self): - if not self.channel: - self.open_channel() - if not self.sudo: - logging.info("Aquiring sudo") - self.channel.send("sudo -s\n") - self._recv_until("%s: " % self.username) - self.channel.send("%s\n" % self.password) - self._recv_until("# ") - self.sudo = True - - def exec_cmd(self, command, sudo=False): + def exec_cmd(self, command): logging.info("Executing command: '%s'" % command) - if not self.channel: - self.open_channel() - if sudo and not self.sudo: - self.aquire_sudo() - self.channel.send("%s\n" % command) - if sudo or self.sudo: - return self._recv_until("# ") - else: - return self._recv_until("$ ") + chan = self.ssh_client.get_transport().open_session() + stdin = chan.makefile('wb') + stdout = chan.makefile('rb') + stderr = chan.makefile_stderr('rb') + cmd = "%s\n" % command + if self.sudo_mode: + cmd = 'sudo -S bash -c "%s"' % cmd.replace('"', '\\"') + chan.exec_command(cmd) + if stdout.channel.closed is False: + stdin.write('%s\n' % self.password) + stdin.flush() + result = { + 'stdout': [], + 'stderr': [], + 'exit_status': chan.recv_exit_status() + } + for line in stdout: + result['stdout'].append(line) + for line in stderr: + result['stderr'].append(line) - def mkdir(self, path, sudo=False): + return result + + def mkdir(self, path): logging.info("Creating directory: %s" % path) - if not sudo: - self.sftp_client.mkdir(path) - else: - self.open_channel() - self.aquire_sudo() - self.channel.send("mkdir %s\n" % path) - self._recv_until("# ") + return self.exec_cmd("mkdir %s\n" % path) - - def rmdir(self, path, sudo=False): + def rmdir(self, path): logging.info("Removing directory: %s" % path) - if not sudo: - self.ssh_client.exec_command("rm -rf %s" % path) - else: - self.open_channel() - self.aquire_sudo() - self.channel.send("rm -rf %s\n" % path) - self._recv_until("# ") + return self.exec_command("rm -rf %s" % path) def scp(self, frm, to): logging.info("Copying file: %s -> %s" % (frm, to)) @@ -119,9 +115,9 @@ class SSHClient(object): curdir = remote_root else: curdir = os.path.join(remote_root, rel) - self.sftp_client.mkdir(curdir) + self.mkdir(curdir) for fl in fls: - self.sftp_client.put( + self.scp( os.path.join(root, fl), os.path.join(curdir, fl) ) @@ -129,10 +125,3 @@ class SSHClient(object): def disconnect(self): self.sftp_client.close() self.ssh_client.close() - - def _recv_until(self, data): - buff = "" - while not buff.endswith(data): - resp = self.channel.recv(9999) - buff += resp - return buff diff --git a/test/integration/test_node.py b/test/integration/test_node.py index 4bf47ba4a..5b2149db3 100644 --- a/test/integration/test_node.py +++ b/test/integration/test_node.py @@ -38,7 +38,49 @@ class TestNode(TestCase): cookbook_remote_path = os.path.join(SAMPLE_REMOTE_PATH, "sample-cook") release_remote_path = os.path.join(SAMPLE_REMOTE_PATH, "sample-release.json") - host = str(ci.environment.node['admin'].ip_address) + logging.info("Starting slave node") + admin_node = ci.environment.node['admin'] + admin_ip = admin_node.ip_address + node = ci.environment.node['slave'] + node.start() + + slave_id = node.interfaces[0].mac_address.replace(":", "").upper() + + while True: + logging.info("Waiting for slave agent to run...") + nodes = json.loads(self.client.get( + "http://%s:8000/api/nodes" % admin_ip + )) + time.sleep(15) + if len(nodes) > 0: + logging.info("Node found") + break + + cluster = json.loads(self.client.post( + "http://%s:8000/api/clusters" % admin_ip, + data='{ "name": "MyOwnPrivateCluster", "release": 1 }', + log=True + )) + + resp = json.loads(self.client.put( + "http://%s:8000/api/clusters/1" % admin_ip, + data='{ "nodes": ["%s"] }' % slave_id + )) + + cluster = json.loads(self.client.get( + "http://%s:8000/api/clusters/1" % admin_ip + )) + if len(cluster["nodes"]) == 0: + raise ValueError("Failed to add node into cluster") + + resp = json.loads(self.client.put( + "http://%s:8000/api/nodes/%s" % (admin_ip, slave_id), + data='{ "new_roles": [1, 2], "redeployment_needed": true }' + )) + if len(resp["new_roles"]) == 0: + raise ValueError("Failed to assign roles to node") + + """ self.remote.connect_ssh(host, "ubuntu", "r00tme") self.remote.rmdir(cookbook_remote_path) @@ -100,56 +142,28 @@ class TestNode(TestCase): for cmd in commands: self.remote.exec_cmd(cmd) - - cluster = json.loads(self.client.post( - "http://%s:8000/api/clusters" % host, - data='{ "name": "MyOwnPrivateCluster", "release": 1 }', - log=True - )) - - nodes = json.loads(self.client.get( - "http://%s:8000/api/nodes" % host - )) - if len(nodes) == 0: - raise ValueError("Nodes list is empty") - node_id = nodes[0]['id'] - - resp = json.loads(self.client.put( - "http://%s:8000/api/clusters/1" % host, - data='{ "nodes": ["%s"] }' % node_id - )) - - cluster = json.loads(self.client.get( - "http://%s:8000/api/clusters/1" % host - )) - if len(cluster["nodes"]) == 0: - raise ValueError("Failed to add node into cluster") - - resp = json.loads(self.client.put( - "http://%s:8000/api/nodes/%s" % (host, node_id), - data='{ "new_roles": [1, 2], "redeployment_needed": true }' - )) - if len(resp["new_roles"]) == 0: - raise ValueError("Failed to assign roles to node") - + """ + logging.info("Provisioning...") task = json.loads(self.client.put( - "http://%s:8000/api/clusters/1/changes/" % host, + "http://%s:8000/api/clusters/1/changes/" % admin_ip, log=True )) task_id = task['task_id'] + logging.info("Task created: %s" % task_id) time.sleep(2) while True: try: task = json.loads(self.client.get( - "http://%s:8000/api/tasks/%s/" % (host, task_id) + "http://%s:8000/api/tasks/%s/" % (admin_ip, task_id) )) self.check_tasks(task) break except StillPendingException: pass + """ # check if recipes executed ret = self.remote.exec_cmd("test -f /tmp/chef_success && echo 'SUCCESS'") if not "SUCCESS" in ret.split("\r\n")[1:]: @@ -168,8 +182,8 @@ class TestNode(TestCase): if not gen_pwd or gen_pwd == 'password': raise Exception("Password generation failed!") - self.remote.disconnect() + """ def check_tasks(self, task): if task['status'] != 'SUCCESS':