new ssh client and install_cookbook missing recipes fix

This commit is contained in:
Nikolay Markov 2012-07-11 16:44:22 +04:00
parent 8f038aaf07
commit f68a00bfa9
4 changed files with 102 additions and 87 deletions

View File

@ -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")

View File

@ -54,6 +54,14 @@ class Ci(object):
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:
logger.error("Failed to build environment: %s\n%s" % (str(e), traceback.format_exc()))

View File

@ -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

View File

@ -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':