rack command uses the cliff framework
Change-Id: I50edf6be8b59ceac39e66cb12cd1048a03230237
This commit is contained in:
parent
fa207dd7e6
commit
7392bbe2ed
|
@ -1,4 +1,5 @@
|
|||
[DEFAULT]
|
||||
test_command=${PYTHON:-python} -m subunit.run discover -t ./ ./ $LISTOPT $IDOPTION
|
||||
test_command=RACK_IS_TEST=1 \
|
||||
${PYTHON:-python} -m subunit.run discover -t ./ ./ $LISTOPT $IDOPTION
|
||||
test_id_option=--load-list $IDFILE
|
||||
test_list_option=--list
|
|
@ -59,10 +59,3 @@ glance_image_id =
|
|||
### Not required params ###
|
||||
#name =
|
||||
|
||||
# Userdata file path like /path/to/file
|
||||
#userdata =
|
||||
|
||||
# Key-value pairs to be passed to metadata server
|
||||
# Syntax: args = key1=value1,key2=value2,...
|
||||
#args =
|
||||
|
||||
|
|
|
@ -146,3 +146,26 @@ class InvalidProcessError(BaseError):
|
|||
|
||||
class ProcessInitError(BaseError):
|
||||
pass
|
||||
|
||||
|
||||
class EndOfFile(Exception):
|
||||
message = 'EOF'
|
||||
|
||||
|
||||
class NoDescriptor(Exception):
|
||||
message = 'Descriptor Not Found'
|
||||
|
||||
def __init__(self, message=None):
|
||||
self.message = message or self.__class__.message
|
||||
|
||||
def __str__(self):
|
||||
formatted_string = self.message
|
||||
return formatted_string
|
||||
|
||||
|
||||
class NoReadDescriptor(NoDescriptor):
|
||||
message = 'Read Descriptor Not Found'
|
||||
|
||||
|
||||
class NoWriteDescriptor(NoDescriptor):
|
||||
message = 'Write Descriptor Not Found'
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
from rackclient import exceptions
|
||||
from rackclient.client import Client
|
||||
|
||||
import cPickle
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import pika
|
||||
import requests
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
META_URL = 'http://169.254.169.254/openstack/latest/meta_data.json'
|
||||
RACK_CTX = None
|
||||
|
||||
|
||||
def get_rack_context(proxy_port=8088, client_version="1", api_version="v1"):
|
||||
global RACK_CTX
|
||||
|
||||
if not RACK_CTX:
|
||||
try:
|
||||
resp = requests.get(META_URL)
|
||||
metadata = json.loads(resp.text)["meta"]
|
||||
proxy_url = 'http://%s:%d/%s' % (metadata["proxy_ip"], proxy_port, api_version)
|
||||
client = Client(client_version, rack_url=proxy_url)
|
||||
proxy_info = client.proxy.get(metadata["gid"])
|
||||
|
||||
RACK_CTX = type('', (object,), metadata)
|
||||
RACK_CTX.ppid = getattr(RACK_CTX, "ppid", "")
|
||||
RACK_CTX.client = client
|
||||
RACK_CTX.fs_endpoint = proxy_info.fs_endpoint
|
||||
RACK_CTX.ipc_endpoint = proxy_info.ipc_endpoint
|
||||
RACK_CTX.shm_endpoint = proxy_info.shm_endpoint
|
||||
|
||||
try:
|
||||
# Check if this process is not recognized by RACK.
|
||||
RACK_CTX.client.processes.get(RACK_CTX.gid, RACK_CTX.pid)
|
||||
except exceptions.NotFound:
|
||||
msg = "This process is not recognized by RACK"
|
||||
raise exceptions.InvalidProcessError(msg)
|
||||
|
||||
if RACK_CTX.ppid:
|
||||
LOG.debug("Messaging: send message to %s", RACK_CTX.ppid)
|
||||
msg = _Messaging(RACK_CTX)
|
||||
msg.send_msg(RACK_CTX.ppid)
|
||||
while True:
|
||||
receive_msg = msg.receive_msg(getattr(RACK_CTX, "msg_limit_time", 180))
|
||||
if receive_msg and RACK_CTX.ppid == receive_msg.get("pid"):
|
||||
LOG.debug("Messaging: receive message from %s", receive_msg.get("pid"))
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
msg = "Failed to initialize the process: %s." % e.message
|
||||
raise exceptions.ProcessInitError(msg)
|
||||
|
||||
return RACK_CTX
|
||||
|
||||
|
||||
class _Messaging(object):
|
||||
|
||||
def __init__(self, ctx):
|
||||
self.ctx = ctx
|
||||
connection_param = pika.ConnectionParameters(self.ctx.proxy_ip)
|
||||
if self.ctx.ipc_endpoint:
|
||||
connection_param = pika.ConnectionParameters(self.ctx.ipc_endpoint)
|
||||
self.connection = pika.BlockingConnection(connection_param)
|
||||
self.channel = self.connection.channel()
|
||||
self.channel.exchange_declare(exchange=ctx.gid, type='topic')
|
||||
self.channel.queue_declare(queue=ctx.pid)
|
||||
self.channel.queue_bind(exchange=ctx.gid, queue=ctx.pid, routing_key=ctx.gid + '.' + ctx.pid)
|
||||
|
||||
|
||||
def receive_msg(self, timeout_limit=180):
|
||||
queue_name = self.ctx.pid
|
||||
self.channel = self.connection.channel()
|
||||
receive = self.Receive()
|
||||
self.connection.add_timeout(deadline=int(timeout_limit), callback_method=receive.time_out)
|
||||
self.channel.basic_consume(receive.get_msg, queue=queue_name, no_ack=False)
|
||||
receive.channel = self.channel
|
||||
self.channel.start_consuming()
|
||||
return receive.message
|
||||
|
||||
|
||||
class Receive(object):
|
||||
|
||||
def __init__(self):
|
||||
self.channel = None
|
||||
self.message = None
|
||||
|
||||
def get_msg(self, ch, method, properties, body):
|
||||
self.message = cPickle.loads(body)
|
||||
ch.basic_ack(delivery_tag=method.delivery_tag)
|
||||
ch.stop_consuming()
|
||||
|
||||
def time_out(self):
|
||||
self.channel.stop_consuming()
|
||||
|
||||
|
||||
def send_msg(self, target):
|
||||
routing_key = self.ctx.gid + '.' + target
|
||||
send_dict = {'pid': self.ctx.pid}
|
||||
send_msg = cPickle.dumps(send_dict)
|
||||
self.channel.basic_publish(exchange=self.ctx.gid, routing_key=routing_key, body=send_msg)
|
||||
|
||||
if not os.environ.get("RACK_IS_TEST"):
|
||||
get_rack_context()
|
|
@ -1,22 +1,23 @@
|
|||
from rackclient.lib import RACK_CTX
|
||||
from rackclient import exceptions
|
||||
from swiftclient import client as swift_client
|
||||
from swiftclient import exceptions as swift_exc
|
||||
|
||||
import json
|
||||
import logging
|
||||
import tempfile
|
||||
from swiftclient import client as swift_client
|
||||
from swiftclient import exceptions as swift_exc
|
||||
from rackclient import process_context
|
||||
from rackclient import exceptions
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
PCTXT = process_context.PCTXT
|
||||
SWIFT_PORT = 8080
|
||||
|
||||
|
||||
def _get_swift_client():
|
||||
if PCTXT.fs_endpoint:
|
||||
|
||||
if RACK_CTX.fs_endpoint:
|
||||
try:
|
||||
d = json.loads(PCTXT.fs_endpoint)
|
||||
d = json.loads(RACK_CTX.fs_endpoint)
|
||||
credentials = {
|
||||
"user": d["os_username"],
|
||||
"key": d["os_password"],
|
||||
|
@ -29,7 +30,7 @@ def _get_swift_client():
|
|||
msg = "The format of fs_endpoint is invalid."
|
||||
raise exceptions.InvalidFSEndpointError(msg)
|
||||
else:
|
||||
authurl = "http://%s:%d/auth/v1.0" % (PCTXT.proxy_ip, SWIFT_PORT)
|
||||
authurl = "http://%s:%d/auth/v1.0" % (RACK_CTX.proxy_ip, SWIFT_PORT)
|
||||
|
||||
credentials = {
|
||||
"user": "rack:admin",
|
||||
|
@ -38,6 +39,7 @@ def _get_swift_client():
|
|||
}
|
||||
swift = swift_client.Connection(**credentials)
|
||||
authurl, token = swift.get_auth()
|
||||
|
||||
return swift_client.Connection(preauthurl=authurl, preauthtoken=token)
|
||||
|
||||
|
||||
|
@ -138,4 +140,4 @@ class File(object):
|
|||
return getattr(self.file, name)
|
||||
else:
|
||||
raise AttributeError("%s instance has no attribute '%s'",
|
||||
self.__class__.__name__, name)
|
||||
self.__class__.__name__, name)
|
|
@ -1,31 +1,33 @@
|
|||
from rackclient.lib import RACK_CTX
|
||||
from rackclient import exceptions
|
||||
|
||||
import cPickle
|
||||
import logging
|
||||
import pika
|
||||
from rackclient import exceptions
|
||||
from rackclient import process_context
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
PCTXT = process_context.PCTXT
|
||||
|
||||
|
||||
class Messaging(object):
|
||||
|
||||
def __init__(self):
|
||||
self.connection = _create_connection()
|
||||
self.connection = self._create_connection()
|
||||
self.channel = self.connection.channel()
|
||||
self.declare_queue(PCTXT.pid)
|
||||
self.declare_queue(RACK_CTX.pid)
|
||||
|
||||
def declare_queue(self, queue_name):
|
||||
queue_name = str(queue_name)
|
||||
self.channel.exchange_declare(exchange=PCTXT.gid, type='topic')
|
||||
self.channel.exchange_declare(exchange=RACK_CTX.gid, type='topic')
|
||||
self.channel.queue_declare(queue=queue_name)
|
||||
self.channel.queue_bind(exchange=PCTXT.gid,
|
||||
self.channel.queue_bind(exchange=RACK_CTX.gid,
|
||||
queue=queue_name,
|
||||
routing_key=PCTXT.gid + '.' + queue_name)
|
||||
routing_key=RACK_CTX.gid + '.' + queue_name)
|
||||
|
||||
def receive_all_msg(self, queue_name=None,
|
||||
timeout_limit=180, msg_limit_count=None):
|
||||
if not queue_name:
|
||||
queue_name = PCTXT.pid
|
||||
queue_name = RACK_CTX.pid
|
||||
|
||||
self.channel = self.connection.channel()
|
||||
receive = self.Receive()
|
||||
|
@ -42,7 +44,7 @@ class Messaging(object):
|
|||
|
||||
def receive_msg(self, queue_name=None, timeout_limit=180):
|
||||
if not queue_name:
|
||||
queue_name = PCTXT.pid
|
||||
queue_name = RACK_CTX.pid
|
||||
self.channel = self.connection.channel()
|
||||
receive = self.Receive()
|
||||
timeout_limit = int(timeout_limit)
|
||||
|
@ -79,36 +81,22 @@ class Messaging(object):
|
|||
self.channel.stop_consuming()
|
||||
|
||||
def send_msg(self, target, message=None):
|
||||
routing_key = PCTXT.gid + '.' + target
|
||||
send_dict = {'pid': PCTXT.pid}
|
||||
routing_key = RACK_CTX.gid + '.' + target
|
||||
send_dict = {'pid': RACK_CTX.pid}
|
||||
if message:
|
||||
send_dict['message'] = message
|
||||
send_msg = cPickle.dumps(send_dict)
|
||||
self.channel.basic_publish(exchange=PCTXT.gid,
|
||||
self.channel.basic_publish(exchange=RACK_CTX.gid,
|
||||
routing_key=routing_key,
|
||||
body=send_msg)
|
||||
|
||||
|
||||
def _create_connection():
|
||||
if PCTXT.ipc_endpoint:
|
||||
connection_param = pika.ConnectionParameters(PCTXT.ipc_endpoint)
|
||||
else:
|
||||
connection_param = pika.ConnectionParameters(PCTXT.proxy_ip)
|
||||
try:
|
||||
connection = pika.BlockingConnection(connection_param)
|
||||
except pika.exceptions.AMQPConnectionError as e:
|
||||
raise exceptions.AMQPConnectionError(e)
|
||||
return connection
|
||||
|
||||
|
||||
def init():
|
||||
msg = Messaging()
|
||||
if PCTXT.ppid:
|
||||
LOG.debug("Messaging: send message to %s", PCTXT.ppid)
|
||||
msg.send_msg(PCTXT.ppid)
|
||||
while True:
|
||||
receive_msg = msg.receive_msg()
|
||||
if receive_msg and PCTXT.ppid == receive_msg.get("pid"):
|
||||
LOG.debug("Messaging: receive message from %s",
|
||||
receive_msg.get("pid"))
|
||||
break
|
||||
def _create_connection(self):
|
||||
if RACK_CTX.ipc_endpoint:
|
||||
connection_param = pika.ConnectionParameters(RACK_CTX.ipc_endpoint)
|
||||
else:
|
||||
connection_param = pika.ConnectionParameters(RACK_CTX.proxy_ip)
|
||||
try:
|
||||
connection = pika.BlockingConnection(connection_param)
|
||||
except pika.exceptions.AMQPConnectionError as e:
|
||||
raise exceptions.AMQPConnectionError(e)
|
||||
return connection
|
|
@ -1,47 +1,17 @@
|
|||
import logging
|
||||
import time
|
||||
from datetime import datetime
|
||||
from rackclient.lib import RACK_CTX
|
||||
from rackclient import exceptions
|
||||
|
||||
import logging
|
||||
import redis
|
||||
from rackclient import process_context
|
||||
import time
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
PCTXT = process_context.PCTXT
|
||||
|
||||
|
||||
class EndOfFile(Exception):
|
||||
message = 'EOF'
|
||||
|
||||
|
||||
class NoDescriptor(Exception):
|
||||
message = 'Descriptor Not Found'
|
||||
|
||||
def __init__(self, message=None):
|
||||
self.message = message or self.__class__.message
|
||||
|
||||
def __str__(self):
|
||||
formatted_string = self.message
|
||||
return formatted_string
|
||||
|
||||
|
||||
class NoReadDescriptor(NoDescriptor):
|
||||
message = 'Read Descriptor Not Found'
|
||||
|
||||
|
||||
class NoWriteDescriptor(NoDescriptor):
|
||||
message = 'Write Descriptor Not Found'
|
||||
|
||||
|
||||
def eof():
|
||||
raise EndOfFile()
|
||||
|
||||
|
||||
def no_reader():
|
||||
raise NoReadDescriptor()
|
||||
|
||||
|
||||
def no_writer():
|
||||
raise NoWriteDescriptor()
|
||||
PIPE = 1
|
||||
FIFO = 2
|
||||
PORT = 6379
|
||||
|
||||
|
||||
def read_state_key(name):
|
||||
|
@ -56,16 +26,13 @@ def reference_key_pattern(name="*", pid="*"):
|
|||
return name + ":" + pid
|
||||
|
||||
|
||||
PIPE = 1
|
||||
FIFO = 2
|
||||
PORT = 6379
|
||||
|
||||
|
||||
class Pipe:
|
||||
|
||||
def __init__(self, name=None, read=None, write=None):
|
||||
now = datetime.now()
|
||||
self.host = PCTXT.proxy_ip
|
||||
self.host = RACK_CTX.proxy_ip
|
||||
self.port = PORT
|
||||
|
||||
if name:
|
||||
self.is_named = True
|
||||
self.r = redis.StrictRedis(host=self.host, port=self.port, db=FIFO)
|
||||
|
@ -75,13 +42,13 @@ class Pipe:
|
|||
else:
|
||||
self.is_named = False
|
||||
self.r = redis.StrictRedis(host=self.host, port=self.port, db=PIPE)
|
||||
parent_pipe = self.r.keys(reference_key_pattern(pid=PCTXT.pid))
|
||||
parent_pipe = self.r.keys(reference_key_pattern(pid=RACK_CTX.pid))
|
||||
if parent_pipe:
|
||||
self.name = self.r.get(parent_pipe[0])
|
||||
else:
|
||||
self.name = PCTXT.pid
|
||||
read_state = self.r.hget(read_state_key(self.name), PCTXT.pid) or now
|
||||
write_state = self.r.hget(write_state_key(self.name), PCTXT.pid) or now
|
||||
self.name = RACK_CTX.pid
|
||||
read_state = self.r.hget(read_state_key(self.name), RACK_CTX.pid) or now
|
||||
write_state = self.r.hget(write_state_key(self.name), RACK_CTX.pid) or now
|
||||
if read is not None:
|
||||
if read:
|
||||
read_state = now
|
||||
|
@ -94,12 +61,12 @@ class Pipe:
|
|||
write_state = "close"
|
||||
self.read_state = read_state
|
||||
self.write_state = write_state
|
||||
self.r.hset(read_state_key(self.name), PCTXT.pid, self.read_state)
|
||||
self.r.hset(write_state_key(self.name), PCTXT.pid, self.write_state)
|
||||
self.r.hset(read_state_key(self.name), RACK_CTX.pid, self.read_state)
|
||||
self.r.hset(write_state_key(self.name), RACK_CTX.pid, self.write_state)
|
||||
|
||||
def read(self):
|
||||
if self.read_state == "close":
|
||||
no_reader()
|
||||
raise exceptions.NoReadDescriptor()
|
||||
data = self._read()
|
||||
while data is None:
|
||||
data = self._read()
|
||||
|
@ -110,26 +77,26 @@ class Pipe:
|
|||
data = self.r.lpop(self.name)
|
||||
if data is None and not self.has_writer():
|
||||
self.flush()
|
||||
eof()
|
||||
raise exceptions.EndOfFile()
|
||||
else:
|
||||
return data
|
||||
|
||||
def write(self, data):
|
||||
if self.write_state == "close":
|
||||
no_writer()
|
||||
raise exceptions.NoWriteDescriptor()
|
||||
self.r.rpush(self.name, data)
|
||||
if self.has_reader():
|
||||
return True
|
||||
else:
|
||||
no_reader()
|
||||
raise exceptions.NoReadDescriptor()
|
||||
|
||||
def close_reader(self):
|
||||
self.read_state = "close"
|
||||
self.r.hset(read_state_key(self.name), PCTXT.pid, self.read_state)
|
||||
self.r.hset(read_state_key(self.name), RACK_CTX.pid, self.read_state)
|
||||
|
||||
def close_writer(self):
|
||||
self.write_state = "close"
|
||||
self.r.hset(write_state_key(self.name), PCTXT.pid, self.write_state)
|
||||
self.r.hset(write_state_key(self.name), RACK_CTX.pid, self.write_state)
|
||||
|
||||
def has_reader(self):
|
||||
read_states = self.r.hvals(read_state_key(self.name))
|
||||
|
@ -158,9 +125,9 @@ class Pipe:
|
|||
self.r.delete(*tuple(keys))
|
||||
|
||||
@classmethod
|
||||
def flush_by_pid(cls, pid, host=None):
|
||||
def flush_by_pid(self, pid, host=None):
|
||||
if not host:
|
||||
host = PCTXT.proxy_ip
|
||||
host = RACK_CTX.proxy_ip
|
||||
|
||||
r = redis.StrictRedis(host=host, port=PORT, db=PIPE)
|
||||
keys = [pid,
|
||||
|
@ -172,7 +139,7 @@ class Pipe:
|
|||
@classmethod
|
||||
def flush_by_name(cls, name, host=None):
|
||||
if not host:
|
||||
host = PCTXT.proxy_ip
|
||||
host = RACK_CTX.proxy_ip
|
||||
|
||||
r = redis.StrictRedis(host=host, port=PORT, db=FIFO)
|
||||
keys = [name,
|
||||
|
@ -183,8 +150,8 @@ class Pipe:
|
|||
@classmethod
|
||||
def share(cls, ppid, pid, host=None):
|
||||
if not host:
|
||||
host = PCTXT.proxy_ip
|
||||
|
||||
host = RACK_CTX.proxy_ip
|
||||
|
||||
now = datetime.now()
|
||||
r = redis.StrictRedis(host=host, port=PORT, db=PIPE)
|
||||
keys = r.keys(reference_key_pattern(pid=ppid))
|
||||
|
@ -205,4 +172,4 @@ class Pipe:
|
|||
current_write_state = now
|
||||
r.hset(read_state_key(name), pid, current_read_state)
|
||||
r.hset(write_state_key(name), pid, current_write_state)
|
||||
return True
|
||||
return True
|
|
@ -1,7 +1,8 @@
|
|||
import logging
|
||||
import redis
|
||||
|
||||
from rackclient import process_context
|
||||
from rackclient.lib import RACK_CTX
|
||||
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -10,7 +11,7 @@ FIFO = 3
|
|||
PORT = 6379
|
||||
|
||||
def get_host():
|
||||
return process_context.PCTXT.proxy_ip
|
||||
return RACK_CTX.proxy_ip
|
||||
|
||||
|
||||
class Shm(object):
|
|
@ -1,10 +1,10 @@
|
|||
import websocket
|
||||
import logging
|
||||
from rackclient import process_context
|
||||
import websocket
|
||||
|
||||
from rackclient.lib import RACK_CTX
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
PCTXT = process_context.PCTXT
|
||||
WS_PORT = 8888
|
||||
|
||||
|
||||
|
@ -13,14 +13,14 @@ class SignalManager(object):
|
|||
if url:
|
||||
self.url = url.rstrip('/')
|
||||
else:
|
||||
self.url = "ws://" + ':'.join([PCTXT.proxy_ip, str(WS_PORT)])
|
||||
self.url = "ws://" + ':'.join([RACK_CTX.proxy_ip, str(WS_PORT)])
|
||||
|
||||
def receive(self, on_msg_func, pid=None):
|
||||
self.on_msg_func = on_msg_func
|
||||
if pid:
|
||||
header = 'PID: ' + pid
|
||||
elif getattr(PCTXT, 'pid', False):
|
||||
header = 'PID: ' + PCTXT.pid
|
||||
elif getattr(RACK_CTX, 'pid', False):
|
||||
header = 'PID: ' + RACK_CTX.pid
|
||||
else:
|
||||
raise Exception("Target PID is required.")
|
||||
wsapp = websocket.WebSocketApp(
|
|
@ -3,14 +3,14 @@ import Queue
|
|||
import threading
|
||||
|
||||
from rackclient import exceptions
|
||||
from rackclient import process_context
|
||||
from rackclient.v1 import processes
|
||||
from rackclient.v1.syscall.default import messaging
|
||||
from rackclient.v1.syscall.default import pipe as rackpipe
|
||||
from rackclient.v1.syscall.default import file as rackfile
|
||||
from rackclient.lib import RACK_CTX
|
||||
from rackclient.lib.syscall.default import messaging
|
||||
from rackclient.lib.syscall.default import pipe as rackpipe
|
||||
from rackclient.lib.syscall.default import file as rackfile
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
PCTXT = process_context.PCTXT
|
||||
|
||||
|
||||
def fork(opt_list, timeout_limit=180):
|
||||
|
@ -20,8 +20,8 @@ def fork(opt_list, timeout_limit=180):
|
|||
return_process_list = []
|
||||
while True:
|
||||
try:
|
||||
child_list = _bulk_fork(PCTXT.pid, opt_list)
|
||||
success_list, error_list = _check_connection(PCTXT.pid,
|
||||
child_list = _bulk_fork(RACK_CTX.pid, opt_list)
|
||||
success_list, error_list = _check_connection(RACK_CTX.pid,
|
||||
child_list,
|
||||
timeout_limit)
|
||||
except Exception as e:
|
||||
|
@ -42,29 +42,39 @@ def fork(opt_list, timeout_limit=180):
|
|||
|
||||
return return_process_list
|
||||
|
||||
def kill(pid):
|
||||
RACK_CTX.client.processes.delete(RACK_CTX.gid, pid)
|
||||
|
||||
def pipe(name=None):
|
||||
p = rackpipe.Pipe(name)
|
||||
return p
|
||||
|
||||
def pipe_reader(name=None):
|
||||
p = rackpipe.Pipe(name)
|
||||
p.close_writer()
|
||||
return p
|
||||
|
||||
def pipe_writer(name=None):
|
||||
p = rackpipe.Pipe(name)
|
||||
p.close_reader()
|
||||
return p
|
||||
|
||||
def fopen(file_path, mode="r"):
|
||||
return rackfile.File(file_path, mode)
|
||||
|
||||
|
||||
def _bulk_fork(pid, args_list):
|
||||
LOG.debug("start bulk_fork")
|
||||
q = Queue.Queue()
|
||||
|
||||
def _fork(pid, **kwargs):
|
||||
try:
|
||||
child = PCTXT.client.processes.create(gid=PCTXT.gid,
|
||||
child = RACK_CTX.client.processes.create(gid=RACK_CTX.gid,
|
||||
ppid=pid,
|
||||
**kwargs)
|
||||
q.put(child)
|
||||
except Exception as e:
|
||||
attr = dict(args=kwargs, error=e)
|
||||
q.put(processes.Process(PCTXT.client, attr))
|
||||
q.put(processes.Process(RACK_CTX.client, attr))
|
||||
|
||||
tg = []
|
||||
process_list = []
|
||||
|
@ -116,7 +126,7 @@ def _check_connection(pid, process_list, timeout):
|
|||
actives.append(process)
|
||||
pid_list.remove(process.pid)
|
||||
else:
|
||||
PCTXT.client.processes.delete(PCTXT.gid, process.pid)
|
||||
RACK_CTX.client.processes.delete(RACK_CTX.gid, process.pid)
|
||||
inactives.append(process)
|
||||
|
||||
LOG.debug("_check_connection active processes count: %s", len(actives))
|
|
@ -1,73 +0,0 @@
|
|||
# Copyright (c) 2014 ITOCHU Techno-Solutions Corporation.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import json
|
||||
import requests
|
||||
from rackclient import client
|
||||
from rackclient.exceptions import MetadataAccessError
|
||||
|
||||
METADATA_URL = 'http://169.254.169.254/openstack/latest/meta_data.json'
|
||||
|
||||
|
||||
class ProcessContext(object):
|
||||
|
||||
def __init__(self):
|
||||
self.gid = None
|
||||
self.pid = None
|
||||
self.ppid = None
|
||||
self.proxy_ip = None
|
||||
self.proxy_url = None
|
||||
self.fs_endpoint = None
|
||||
self.shm_endpoint = None
|
||||
self.ipc_endpoint = None
|
||||
self.client = None
|
||||
|
||||
def add_args(self, args):
|
||||
if isinstance(args, dict):
|
||||
for (k, v) in args.items():
|
||||
try:
|
||||
setattr(self, k, v)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
PCTXT = ProcessContext()
|
||||
|
||||
|
||||
def _get_metadata(metadata_url):
|
||||
try:
|
||||
resp = requests.get(metadata_url)
|
||||
except Exception as e:
|
||||
msg = "Could not get the metadata: %s" % e.message
|
||||
raise MetadataAccessError(msg)
|
||||
|
||||
body = json.loads(resp.text)
|
||||
return body['meta']
|
||||
|
||||
|
||||
def init(client_version='1', proxy_port=8088, api_version='v1'):
|
||||
metadata = _get_metadata(METADATA_URL)
|
||||
|
||||
PCTXT.gid = metadata.pop('gid')
|
||||
PCTXT.pid = metadata.pop('pid')
|
||||
PCTXT.ppid = metadata.pop('ppid') if 'ppid' in metadata else None
|
||||
PCTXT.proxy_ip = metadata.pop('proxy_ip')
|
||||
PCTXT.proxy_url = 'http://%s:%d/%s' % \
|
||||
(PCTXT.proxy_ip, proxy_port, api_version)
|
||||
PCTXT.client = client.Client(client_version, rack_url=PCTXT.proxy_url)
|
||||
PCTXT.add_args(metadata)
|
||||
|
||||
proxy_info = PCTXT.client.proxy.get(PCTXT.gid)
|
||||
PCTXT.fs_endpoint = proxy_info.fs_endpoint
|
||||
PCTXT.shm_endpoint = proxy_info.shm_endpoint
|
||||
PCTXT.ipc_endpoint = proxy_info.ipc_endpoint
|
|
@ -1,201 +1,93 @@
|
|||
# Copyright (c) 2014 ITOCHU Techno-Solutions Corporation.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""
|
||||
Command-line interface to the RACK API.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import logging
|
||||
from oslo.utils import encodeutils
|
||||
from rackclient.openstack.common.gettextutils import _
|
||||
from rackclient.openstack.common import cliutils
|
||||
from rackclient.v1 import shell as shell_v1
|
||||
from rackclient import client
|
||||
import os
|
||||
import sys
|
||||
|
||||
from cliff.app import App
|
||||
from cliff.commandmanager import CommandManager
|
||||
import requests
|
||||
|
||||
from rackclient import exceptions
|
||||
|
||||
DEFAULT_RACK_API_VERSION = "1"
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
VERSION='1'
|
||||
|
||||
|
||||
class RackShell(object):
|
||||
class RackShell(App):
|
||||
|
||||
def get_base_parser(self):
|
||||
parser = argparse.ArgumentParser(
|
||||
prog='rack',
|
||||
description=__doc__.strip(),
|
||||
epilog='See "rack help COMMAND" '
|
||||
'for help on a specific command.',
|
||||
add_help=False,
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
def __init__(self):
|
||||
super(RackShell, self).__init__(
|
||||
description='rack shell',
|
||||
version=VERSION,
|
||||
command_manager=CommandManager('rack.command'),
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'-h', '--help',
|
||||
action='store_true',
|
||||
help=argparse.SUPPRESS
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--version',
|
||||
action='version'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'-d', '--debug',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help=_("Print debugging output")
|
||||
)
|
||||
def build_option_parser(self, description, version,
|
||||
argparse_kwargs=None):
|
||||
parser = super(RackShell, self).build_option_parser(
|
||||
description, version, argparse_kwargs)
|
||||
|
||||
parser.add_argument(
|
||||
'--rack-api-version',
|
||||
metavar='<rack-api-ver>',
|
||||
default=cliutils.env('RACK_API_VERSION',
|
||||
default=DEFAULT_RACK_API_VERSION),
|
||||
help=_('Accepts only 1, '
|
||||
'defaults to env[RACK_API_VERSION].'))
|
||||
|
||||
metavar='<api-verion>',
|
||||
default=os.environ.get('RACK_API_VERSION', VERSION),
|
||||
help=('Accepts only 1, '
|
||||
'defaults to env[RACK_API_VERSION].')
|
||||
)
|
||||
parser.add_argument(
|
||||
'--rack-url',
|
||||
metavar='<rack-url>',
|
||||
default=cliutils.env('RACK_URL'),
|
||||
help=_('Defaults to env[RACK_URL].'))
|
||||
|
||||
default=os.environ.get('RACK_URL', ''),
|
||||
help='Defaults to env[RACK_URL].'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--gid',
|
||||
metavar='<gid>',
|
||||
default=cliutils.env('RACK_GID'),
|
||||
help=_('Defaults to env[RACK_GID].'))
|
||||
default=os.environ.get('RACK_GID', ''),
|
||||
help='Defaults to env[RACK_GID].'
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def get_subcommand_parser(self, version):
|
||||
parser = self.get_base_parser()
|
||||
def configure_logging(self):
|
||||
super(RackShell, self).configure_logging()
|
||||
|
||||
self.subcommands = {}
|
||||
subparsers = parser.add_subparsers(metavar='<subcommand>')
|
||||
rlogger = logging.getLogger(requests.__name__)
|
||||
rlogger.setLevel(logging.WARNING)
|
||||
|
||||
try:
|
||||
actions_module = {
|
||||
'1': shell_v1,
|
||||
}[version]
|
||||
except KeyError:
|
||||
actions_module = shell_v1
|
||||
def initialize_app(self, argv):
|
||||
self.check_options()
|
||||
|
||||
self._find_actions(subparsers, actions_module)
|
||||
self._find_actions(subparsers, self)
|
||||
def check_options(self):
|
||||
if self.options.rack_api_version != '1':
|
||||
raise exceptions.CommandError(
|
||||
"'rack-api-version' must be 1")
|
||||
|
||||
return parser
|
||||
if not self.options.rack_url:
|
||||
raise exceptions.CommandError(
|
||||
"You must provide an RACK url "
|
||||
"via either --rack-url or env[RACK_URL]")
|
||||
|
||||
def _find_actions(self, subparsers, actions_module):
|
||||
for attr in (a for a in dir(actions_module) if a.startswith('do_')):
|
||||
command = attr[3:].replace('_', '-')
|
||||
callback = getattr(actions_module, attr)
|
||||
desc = callback.__doc__ or ''
|
||||
action_help = desc.strip()
|
||||
arguments = getattr(callback, 'arguments', [])
|
||||
|
||||
subparser = subparsers.add_parser(
|
||||
command,
|
||||
help=action_help,
|
||||
description=desc,
|
||||
add_help=False,
|
||||
)
|
||||
subparser.add_argument(
|
||||
'-h', '--help',
|
||||
action='help',
|
||||
help=argparse.SUPPRESS,
|
||||
)
|
||||
self.subcommands[command] = subparser
|
||||
for (args, kwargs) in arguments:
|
||||
subparser.add_argument(*args, **kwargs)
|
||||
subparser.set_defaults(func=callback)
|
||||
|
||||
def setup_debugging(self, debug):
|
||||
if not debug:
|
||||
return
|
||||
|
||||
streamformat = "%(levelname)s (%(module)s:%(lineno)d) %(message)s"
|
||||
logging.basicConfig(level=logging.DEBUG,
|
||||
format=streamformat)
|
||||
|
||||
@cliutils.arg('command', metavar='<subcommand>', nargs='?',
|
||||
help='Display help for <subcommand>')
|
||||
def do_help(self, args):
|
||||
"""
|
||||
Display help about this program or one of its subcommands.
|
||||
"""
|
||||
if args.command:
|
||||
if args.command in self.subcommands:
|
||||
self.subcommands[args.command].print_help()
|
||||
else:
|
||||
def prepare_to_run_command(self, cmd):
|
||||
commands = ['HelpCommand', 'ListGroups', 'ShowGroup',
|
||||
'CreateGroup', 'UpdateGroup', 'DeleteGroup',
|
||||
'InitGroup']
|
||||
if cmd.__class__.__name__ not in commands:
|
||||
if not self.options.gid:
|
||||
raise exceptions.CommandError(
|
||||
_("'%s' is not a valid subcommand") % args.command)
|
||||
else:
|
||||
self.parser.print_help()
|
||||
"You must provide a gid "
|
||||
"via either --gid or env[RACK_GID]")
|
||||
|
||||
def main(self, argv):
|
||||
parser = self.get_base_parser()
|
||||
(options, args) = parser.parse_known_args(argv)
|
||||
self.setup_debugging(options.debug)
|
||||
|
||||
subcommand_parser = self.get_subcommand_parser(
|
||||
options.rack_api_version)
|
||||
self.parser = subcommand_parser
|
||||
|
||||
if options.help or not argv:
|
||||
subcommand_parser.print_help()
|
||||
return 0
|
||||
|
||||
args = subcommand_parser.parse_args(argv)
|
||||
|
||||
if args.func == self.do_help:
|
||||
self.do_help(args)
|
||||
return 0
|
||||
|
||||
if not args.rack_url:
|
||||
raise exceptions.CommandError(
|
||||
_("You must provide an RACK url "
|
||||
"via either --rack-url or env[RACK_URL] "))
|
||||
|
||||
self.cs = client.Client(options.rack_api_version, rack_url=args.rack_url, http_log_debug=options.debug)
|
||||
|
||||
if args.func.func_name[3:].split('_')[0] != 'group' and not args.gid:
|
||||
raise exceptions.CommandError(
|
||||
_("You must provide a gid "
|
||||
"via either --gid or env[RACK_GID] "))
|
||||
|
||||
args.func(self.cs, args)
|
||||
def clean_up(self, cmd, result, err):
|
||||
if err:
|
||||
self.log.debug('got an error: %s', err)
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
argv = [encodeutils.safe_decode(a) for a in sys.argv[1:]]
|
||||
RackShell().main(argv)
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(e, exc_info=1)
|
||||
details = {'name': encodeutils.safe_encode(e.__class__.__name__),
|
||||
'msg': encodeutils.safe_encode(unicode(e))}
|
||||
print >> sys.stderr, "ERROR (%(name)s): %(msg)s" % details
|
||||
sys.exit(1)
|
||||
except KeyboardInterrupt as e:
|
||||
print >> sys.stderr, ("Shutting down rackclient")
|
||||
sys.exit(1)
|
||||
def main(argv=sys.argv[1:]):
|
||||
app = RackShell()
|
||||
return app.run(argv)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv[1:]))
|
||||
|
||||
|
|
|
@ -1,128 +0,0 @@
|
|||
import re
|
||||
import StringIO
|
||||
import sys
|
||||
import fixtures
|
||||
import mock
|
||||
from testtools import matchers
|
||||
from rackclient import exceptions
|
||||
import rackclient.shell
|
||||
from rackclient.tests import utils
|
||||
|
||||
FAKE_ENV = {'RACK_URL': 'http://www.example.com:8088/v1',
|
||||
'RACK_GID': '11111111'}
|
||||
|
||||
class ShellTest(utils.TestCase):
|
||||
|
||||
def make_env(self, exclude=None, fake_env=FAKE_ENV):
|
||||
env = dict((k, v) for k, v in fake_env.items() if k != exclude)
|
||||
self.useFixture(fixtures.MonkeyPatch('os.environ', env))
|
||||
|
||||
def shell(self, argstr, exitcodes=(0,)):
|
||||
orig = sys.stdout
|
||||
orig_stderr = sys.stderr
|
||||
try:
|
||||
sys.stdout = StringIO.StringIO()
|
||||
sys.stderr = StringIO.StringIO()
|
||||
_shell = rackclient.shell.RackShell()
|
||||
_shell.main(argstr.split())
|
||||
except SystemExit:
|
||||
exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||
self.assertIn(exc_value.code, exitcodes)
|
||||
finally:
|
||||
stdout = sys.stdout.getvalue()
|
||||
sys.stdout.close()
|
||||
sys.stdout = orig
|
||||
stderr = sys.stderr.getvalue()
|
||||
sys.stderr.close()
|
||||
sys.stderr = orig_stderr
|
||||
return (stdout, stderr)
|
||||
|
||||
def test_help(self):
|
||||
required = [
|
||||
'.*?^usage: ',
|
||||
'.*?^\s+process-show\s+Show details about the given process',
|
||||
'.*?^See "rack help COMMAND" for help on a specific command',
|
||||
]
|
||||
stdout, stderr = self.shell('help')
|
||||
for r in required:
|
||||
self.assertThat((stdout + stderr),
|
||||
matchers.MatchesRegex(r, re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_help_unknown_command(self):
|
||||
self.assertRaises(exceptions.CommandError, self.shell, 'help foofoo')
|
||||
|
||||
def test_help_on_subcommand(self):
|
||||
required = [
|
||||
'.*?^usage: ',
|
||||
'.*?^Show details about the given process',
|
||||
'.*?^positional arguments:',
|
||||
]
|
||||
stdout, stderr = self.shell('help process-show')
|
||||
for r in required:
|
||||
self.assertThat((stdout + stderr),
|
||||
matchers.MatchesRegex(r, re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_help_no_options(self):
|
||||
required = [
|
||||
'.*?^usage: ',
|
||||
'.*?^\s+process-show\s+Show details about the given process',
|
||||
'.*?^See "rack help COMMAND" for help on a specific command',
|
||||
]
|
||||
stdout, stderr = self.shell('')
|
||||
for r in required:
|
||||
self.assertThat((stdout + stderr),
|
||||
matchers.MatchesRegex(r, re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_no_url(self):
|
||||
required = ('You must provide an RACK url '
|
||||
'via either --rack-url or env[RACK_URL] ')
|
||||
self.make_env(exclude='RACK_URL')
|
||||
try:
|
||||
self.shell('process-list')
|
||||
except exceptions.CommandError as message:
|
||||
self.assertEqual(required, message.args[0])
|
||||
else:
|
||||
self.fail('CommandError not raised')
|
||||
|
||||
def test_no_gid(self):
|
||||
required = ('You must provide a gid '
|
||||
'via either --gid or env[RACK_GID] ')
|
||||
self.make_env(exclude='RACK_GID')
|
||||
try:
|
||||
self.shell('process-list')
|
||||
except exceptions.CommandError as message:
|
||||
self.assertEqual(required, message.args[0])
|
||||
else:
|
||||
self.fail('CommandError not raised')
|
||||
|
||||
@mock.patch('sys.argv', ['rack'])
|
||||
@mock.patch('sys.stdout', StringIO.StringIO())
|
||||
@mock.patch('sys.stderr', StringIO.StringIO())
|
||||
def test_main_noargs(self):
|
||||
# Ensure that main works with no command-line arguments
|
||||
try:
|
||||
rackclient.shell.main()
|
||||
except SystemExit:
|
||||
self.fail('Unexpected SystemExit')
|
||||
|
||||
# We expect the normal usage as a result
|
||||
self.assertIn('Command-line interface to the RACK API',
|
||||
sys.stdout.getvalue())
|
||||
|
||||
@mock.patch('sys.stderr', StringIO.StringIO())
|
||||
@mock.patch.object(rackclient.shell.RackShell, 'main')
|
||||
def test_main_exception(self, mock_rack_shell):
|
||||
mock_rack_shell.side_effect = exceptions.CommandError('error message')
|
||||
try:
|
||||
rackclient.shell.main()
|
||||
except SystemExit as ex:
|
||||
self.assertEqual(ex.code, 1)
|
||||
self.assertIn('ERROR (CommandError): error message', sys.stderr.getvalue())
|
||||
|
||||
@mock.patch.object(rackclient.shell.RackShell, 'main')
|
||||
def test_main_keyboard_interrupt(self, mock_rack_shell):
|
||||
mock_rack_shell.side_effect = KeyboardInterrupt()
|
||||
try:
|
||||
rackclient.shell.main()
|
||||
except SystemExit as ex:
|
||||
self.assertEqual(ex.code, 1)
|
|
@ -14,33 +14,31 @@
|
|||
from fixtures import fixture
|
||||
import requests
|
||||
import testtools
|
||||
from rackclient import process_context
|
||||
from rackclient import client
|
||||
|
||||
PCTXT = process_context.PCTXT
|
||||
from mock import *
|
||||
|
||||
|
||||
class PContextFixture(fixture.Fixture):
|
||||
|
||||
def setUp(self):
|
||||
super(PContextFixture, self).setUp()
|
||||
self.attrs = dir(PCTXT)
|
||||
self.addCleanup(self.cleanup_pctxt)
|
||||
|
||||
PCTXT.gid = 'gid'
|
||||
PCTXT.pid = 'pid'
|
||||
PCTXT.ppid = None
|
||||
PCTXT.proxy_ip = '10.0.0.2'
|
||||
PCTXT.proxy_url = 'http://10.0.0.2:8088/v1'
|
||||
PCTXT.fs_endpoint = None
|
||||
PCTXT.shm_endpoint = None
|
||||
PCTXT.ipc_endpoint = None
|
||||
PCTXT.client = client.Client('1', rack_url=PCTXT.proxy_url)
|
||||
|
||||
def cleanup_pctxt(self):
|
||||
attrs = dir(PCTXT)
|
||||
for attr in attrs:
|
||||
if attr not in self.attrs: delattr(PCTXT, attr)
|
||||
# class PContextFixture(fixture.Fixture):
|
||||
#
|
||||
# def setUp(self):
|
||||
# super(PContextFixture, self).setUp()
|
||||
# self.attrs = dir(PCTXT)
|
||||
# self.addCleanup(self.cleanup_pctxt)
|
||||
#
|
||||
# PCTXT.gid = 'gid'
|
||||
# PCTXT.pid = 'pid'
|
||||
# PCTXT.ppid = None
|
||||
# PCTXT.proxy_ip = '10.0.0.2'
|
||||
# PCTXT.proxy_url = 'http://10.0.0.2:8088/v1'
|
||||
# PCTXT.fs_endpoint = None
|
||||
# PCTXT.shm_endpoint = None
|
||||
# PCTXT.ipc_endpoint = None
|
||||
# PCTXT.client = client.Client('1', rack_url=PCTXT.proxy_url)
|
||||
#
|
||||
# def cleanup_pctxt(self):
|
||||
# attrs = dir(PCTXT)
|
||||
# for attr in attrs:
|
||||
# if attr not in self.attrs: delattr(PCTXT, attr)
|
||||
|
||||
|
||||
class TestCase(testtools.TestCase):
|
||||
|
@ -56,9 +54,32 @@ class TestCase(testtools.TestCase):
|
|||
# stderr = self.useFixture(fixtures.StringStream('stderr')).stream
|
||||
# self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
|
||||
|
||||
self.useFixture(PContextFixture())
|
||||
# self.useFixture(PContextFixture())
|
||||
|
||||
|
||||
class LibTestCase(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(LibTestCase, self).setUp()
|
||||
patcher = patch("rackclient.lib." + self.target_context() + ".RACK_CTX")
|
||||
self.addCleanup(patcher.stop)
|
||||
self.mock_RACK_CTX = patcher.start()
|
||||
self._init_context()
|
||||
|
||||
def _init_context(self):
|
||||
self.mock_RACK_CTX.gid="gid"
|
||||
self.mock_RACK_CTX.pid="pid"
|
||||
self.mock_RACK_CTX.ppid=None
|
||||
self.mock_RACK_CTX.proxy_ip="10.0.0.2"
|
||||
self.mock_RACK_CTX.proxy_url = 'http://10.0.0.2:8088/v1'
|
||||
self.mock_RACK_CTX.client = client.Client('1', rack_url=self.mock_RACK_CTX.proxy_url)
|
||||
self.mock_RACK_CTX.fs_endpoint = None
|
||||
self.mock_RACK_CTX.ipc_endpoint = None
|
||||
self.mock_RACK_CTX.shm_endpoint = None
|
||||
|
||||
def target_context(self):
|
||||
pass
|
||||
|
||||
class TestResponse(requests.Response):
|
||||
"""
|
||||
Class used to wrap requests.Response and provide some
|
||||
|
|
|
@ -11,20 +11,21 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from mock import patch
|
||||
from swiftclient import exceptions as swift_exc
|
||||
|
||||
from mock import patch
|
||||
from rackclient.tests import utils
|
||||
from rackclient.v1.syscall.default import file as rackfile
|
||||
from rackclient import process_context
|
||||
from rackclient.lib.syscall.default import file as rackfile
|
||||
from rackclient.exceptions import InvalidFSEndpointError
|
||||
from rackclient.exceptions import InvalidDirectoryError
|
||||
from rackclient.exceptions import InvalidFilePathError
|
||||
from rackclient.exceptions import FileSystemAccessError
|
||||
|
||||
PCTXT = process_context.PCTXT
|
||||
|
||||
class FileTest(utils.LibTestCase):
|
||||
|
||||
class FileTest(utils.TestCase):
|
||||
def target_context(self):
|
||||
return "syscall.default.file"
|
||||
|
||||
def setUp(self):
|
||||
super(FileTest, self).setUp()
|
||||
|
@ -49,7 +50,7 @@ class FileTest(utils.TestCase):
|
|||
'"os_password": "password", '
|
||||
'"os_tenant_name": "tenant", '
|
||||
'"os_auth_url": "http://www.example.com:5000/v2.0"}')
|
||||
PCTXT.fs_endpoint = endpoint
|
||||
self.mock_RACK_CTX.fs_endpoint = endpoint
|
||||
rackfile._get_swift_client()
|
||||
expected = {
|
||||
"user": 'user',
|
||||
|
@ -61,7 +62,7 @@ class FileTest(utils.TestCase):
|
|||
self.mock_conn.assert_any_call(**expected)
|
||||
|
||||
def test_get_swift_client_invalid_fs_endpoint_error(self):
|
||||
PCTXT.fs_endpoint = 'invalid'
|
||||
self.mock_RACK_CTX.fs_endpoint = 'invalid'
|
||||
self.assertRaises(InvalidFSEndpointError, rackfile._get_swift_client)
|
||||
|
||||
def test_listdir(self):
|
||||
|
|
|
@ -11,20 +11,21 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from mock import patch, Mock
|
||||
from rackclient import exceptions
|
||||
from rackclient import process_context
|
||||
from rackclient.tests import utils
|
||||
from rackclient.v1.syscall.default import messaging as rack_ipc
|
||||
|
||||
import copy
|
||||
import cPickle
|
||||
|
||||
import pika
|
||||
|
||||
PCTXT = process_context.PCTXT
|
||||
from mock import patch, Mock
|
||||
from rackclient import exceptions
|
||||
from rackclient.tests import utils
|
||||
from rackclient.lib.syscall.default import messaging as rack_ipc
|
||||
|
||||
|
||||
class MessagingTest(utils.TestCase):
|
||||
class MessagingTest(utils.LibTestCase):
|
||||
|
||||
def target_context(self):
|
||||
return "syscall.default.messaging"
|
||||
|
||||
def setUp(self):
|
||||
super(MessagingTest, self).setUp()
|
||||
|
@ -44,15 +45,15 @@ class MessagingTest(utils.TestCase):
|
|||
msg.declare_queue(queue_name)
|
||||
|
||||
self.mock_channel.\
|
||||
exchange_declare.assert_called_with(exchange=PCTXT.gid,
|
||||
exchange_declare.assert_called_with(exchange=self.mock_RACK_CTX.gid,
|
||||
type='topic')
|
||||
self.mock_channel.queue_declare.assert_called_with(queue=queue_name)
|
||||
r_key = PCTXT.gid + '.' + queue_name
|
||||
self.mock_channel.queue_bind.assert_called_with(exchange=PCTXT.gid,
|
||||
r_key = self.mock_RACK_CTX.gid + '.' + queue_name
|
||||
self.mock_channel.queue_bind.assert_called_with(exchange=self.mock_RACK_CTX.gid,
|
||||
queue=queue_name,
|
||||
routing_key=r_key)
|
||||
|
||||
@patch('rackclient.v1.syscall.default.messaging.Messaging.Receive')
|
||||
@patch('rackclient.lib.syscall.default.messaging.Messaging.Receive')
|
||||
def test_receive_all_msg(self, mock_receive):
|
||||
timeout_limit = 123
|
||||
msg = rack_ipc.Messaging()
|
||||
|
@ -63,12 +64,12 @@ class MessagingTest(utils.TestCase):
|
|||
callback_method=mock_receive().time_out)
|
||||
self.mock_channel.\
|
||||
basic_consume.assert_called_with(mock_receive().get_all_msg,
|
||||
queue=PCTXT.pid,
|
||||
queue=self.mock_RACK_CTX.pid,
|
||||
no_ack=False)
|
||||
self.mock_channel.start_consuming.assert_called_with()
|
||||
self.assertEqual(msg_list, mock_receive().message_list)
|
||||
|
||||
@patch('rackclient.v1.syscall.default.messaging.Messaging.Receive')
|
||||
@patch('rackclient.lib.syscall.default.messaging.Messaging.Receive')
|
||||
def test_receive_msg(self, mock_receive):
|
||||
timeout_limit = 123
|
||||
msg = rack_ipc.Messaging()
|
||||
|
@ -79,7 +80,7 @@ class MessagingTest(utils.TestCase):
|
|||
callback_method=mock_receive().time_out)
|
||||
self.mock_channel.\
|
||||
basic_consume.assert_called_with(mock_receive().get_msg,
|
||||
queue=PCTXT.pid,
|
||||
queue=self.mock_RACK_CTX.pid,
|
||||
no_ack=False)
|
||||
self.mock_channel.start_consuming.assert_called_with()
|
||||
self.assertEqual(message, mock_receive().message)
|
||||
|
@ -90,12 +91,12 @@ class MessagingTest(utils.TestCase):
|
|||
msg = rack_ipc.Messaging()
|
||||
msg.send_msg(target,
|
||||
message=send_msg)
|
||||
routing_key = PCTXT.gid + '.' + target
|
||||
send_dict = {'pid': PCTXT.pid,
|
||||
routing_key = self.mock_RACK_CTX.gid + '.' + target
|
||||
send_dict = {'pid': self.mock_RACK_CTX.pid,
|
||||
'message': send_msg}
|
||||
send_msg = cPickle.dumps(send_dict)
|
||||
self.mock_channel.\
|
||||
basic_publish.assert_called_with(exchange=PCTXT.gid,
|
||||
basic_publish.assert_called_with(exchange=self.mock_RACK_CTX.gid,
|
||||
routing_key=routing_key,
|
||||
body=send_msg)
|
||||
|
||||
|
@ -103,12 +104,12 @@ class MessagingTest(utils.TestCase):
|
|||
msg = rack_ipc.Messaging()
|
||||
target = 'test_pid'
|
||||
msg.send_msg(target)
|
||||
routing_key = PCTXT.gid + '.' + target
|
||||
send_dict = {'pid': PCTXT.pid}
|
||||
routing_key = self.mock_RACK_CTX.gid + '.' + target
|
||||
send_dict = {'pid': self.mock_RACK_CTX.pid}
|
||||
send_msg = cPickle.dumps(send_dict)
|
||||
|
||||
self.mock_channel.\
|
||||
basic_publish.assert_called_with(exchange=PCTXT.gid,
|
||||
basic_publish.assert_called_with(exchange=self.mock_RACK_CTX.gid,
|
||||
routing_key=routing_key,
|
||||
body=send_msg)
|
||||
|
||||
|
@ -175,39 +176,39 @@ class MessagingTest(utils.TestCase):
|
|||
receive.time_out()
|
||||
self.mock_channel.stop_consuming.assert_called_with()
|
||||
|
||||
@patch('rackclient.v1.syscall.default.messaging.Messaging',
|
||||
autospec=True)
|
||||
def test_init(self, msg):
|
||||
rack_ipc.init()
|
||||
msg.assert_called_with()
|
||||
#@patch('rackclient.v1.syscall.default.messaging.Messaging',
|
||||
# autospec=True)
|
||||
# def test_init(self, msg):
|
||||
# rack_ipc.init()
|
||||
# msg.assert_called_with()
|
||||
#
|
||||
# @patch('rackclient.v1.syscall.default.messaging.Messaging',
|
||||
# autospec=True)
|
||||
# def test_init_child(self, msg):
|
||||
# self.mock_RACK_CTX.ppid = 'PPID'
|
||||
# receive_msg = {'pid': self.mock_RACK_CTX.ppid}
|
||||
# mock_messaging = Mock()
|
||||
# msg.return_value = mock_messaging
|
||||
# mock_messaging.receive_msg.return_value = receive_msg
|
||||
# rack_ipc.init()
|
||||
# mock_messaging.send_msg.asset_called_with(self.mock_RACK_CTX.ppid)
|
||||
# mock_messaging.receive_msg.assert_called_onece_with()
|
||||
|
||||
@patch('rackclient.v1.syscall.default.messaging.Messaging',
|
||||
autospec=True)
|
||||
def test_init_child(self, msg):
|
||||
PCTXT.ppid = 'PPID'
|
||||
receive_msg = {'pid': PCTXT.ppid}
|
||||
mock_messaging = Mock()
|
||||
msg.return_value = mock_messaging
|
||||
mock_messaging.receive_msg.return_value = receive_msg
|
||||
rack_ipc.init()
|
||||
mock_messaging.send_msg.asset_called_with(PCTXT.ppid)
|
||||
mock_messaging.receive_msg.assert_called_onece_with()
|
||||
|
||||
@patch('pika.ConnectionParameters', autospec=True)
|
||||
def test_create_connection(self, mock_pika_connection_param):
|
||||
rack_ipc._create_connection()
|
||||
mock_pika_connection_param.assert_called_with(PCTXT.proxy_ip)
|
||||
|
||||
@patch('pika.ConnectionParameters', autospec=True)
|
||||
def test_create_connection_ipc_endpoint(self, mock_pika_connection_param):
|
||||
ipc_ip = 'ipc_ip'
|
||||
PCTXT.ipc_endpoint = ipc_ip
|
||||
|
||||
rack_ipc._create_connection()
|
||||
mock_pika_connection_param.assert_called_with(ipc_ip)
|
||||
|
||||
def test_create_connection_amqp_connection_error(self):
|
||||
self.mock_pika_blocking.side_effect = pika.\
|
||||
exceptions.AMQPConnectionError()
|
||||
self.assertRaises(exceptions.AMQPConnectionError,
|
||||
rack_ipc._create_connection)
|
||||
# @patch('pika.ConnectionParameters', autospec=True)
|
||||
# def test_create_connection(self, mock_pika_connection_param):
|
||||
# rack_ipc._create_connection()
|
||||
# mock_pika_connection_param.assert_called_with(self.mock_RACK_CTX.proxy_ip)
|
||||
#
|
||||
# @patch('pika.ConnectionParameters', autospec=True)
|
||||
# def test_create_connection_ipc_endpoint(self, mock_pika_connection_param):
|
||||
# ipc_ip = 'ipc_ip'
|
||||
# self.mock_RACK_CTX.ipc_endpoint = ipc_ip
|
||||
#
|
||||
# rack_ipc._create_connection()
|
||||
# mock_pika_connection_param.assert_called_with(ipc_ip)
|
||||
#
|
||||
# def test_create_connection_amqp_connection_error(self):
|
||||
# self.mock_pika_blocking.side_effect = pika.\
|
||||
# exceptions.AMQPConnectionError()
|
||||
# self.assertRaises(exceptions.AMQPConnectionError,
|
||||
# rack_ipc._create_connection)
|
|
@ -11,16 +11,19 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import datetime
|
||||
|
||||
from rackclient import exceptions
|
||||
from mock import patch
|
||||
from rackclient.tests import utils
|
||||
from rackclient.v1.syscall.default import pipe
|
||||
from rackclient import process_context
|
||||
import datetime
|
||||
|
||||
PCTXT = process_context.PCTXT
|
||||
|
||||
class PipeTest(utils.TestCase):
|
||||
|
||||
from rackclient.lib.syscall.default import pipe
|
||||
|
||||
|
||||
class PipeTest(utils.LibTestCase):
|
||||
|
||||
def target_context(self):
|
||||
return "syscall.default.pipe"
|
||||
|
||||
def setUp(self):
|
||||
super(PipeTest, self).setUp()
|
||||
patcher = patch('redis.StrictRedis')
|
||||
|
@ -100,13 +103,13 @@ class PipeTest(utils.TestCase):
|
|||
self.ins_redis.lpop.return_value = None
|
||||
self.ins_redis.hvals.return_value = ["close","close"]
|
||||
real = pipe.Pipe(read="read", write="write")
|
||||
self.assertRaises(pipe.EndOfFile, real.read)
|
||||
self.assertRaises(exceptions.EndOfFile, real.read)
|
||||
|
||||
def test_read_NoReadDescriptor(self):
|
||||
self.ins_redis.lpop.return_value = None
|
||||
self.ins_redis.hvals.return_value = ["close","close"]
|
||||
real = pipe.Pipe(read="", write="")
|
||||
self.assertRaises(pipe.NoReadDescriptor, real.read)
|
||||
self.assertRaises(exceptions.NoReadDescriptor, real.read)
|
||||
|
||||
def test_write(self):
|
||||
real = pipe.Pipe(read="read",write="write")
|
||||
|
@ -117,13 +120,13 @@ class PipeTest(utils.TestCase):
|
|||
def test_write_NoReadDescriptor(self):
|
||||
real = pipe.Pipe(read="read",write="write")
|
||||
self.ins_redis.hvals.return_value = ["close","close"]
|
||||
self.assertRaises(pipe.NoReadDescriptor, real.write, "data")
|
||||
self.assertRaises(exceptions.NoReadDescriptor, real.write, "data")
|
||||
self.assertTrue(self.ins_redis.rpush.call_count == 1)
|
||||
|
||||
def test_write_NoWriteDescriptor(self):
|
||||
real = pipe.Pipe(read="",write="")
|
||||
self.ins_redis.hvals.return_value = ["close","close"]
|
||||
self.assertRaises(pipe.NoWriteDescriptor, real.write, "data")
|
||||
self.assertRaises(exceptions.NoWriteDescriptor, real.write, "data")
|
||||
self.assertTrue(self.ins_redis.rpush.call_count == 0)
|
||||
|
||||
def test_close_reader(self):
|
||||
|
@ -214,7 +217,7 @@ class PipeTest(utils.TestCase):
|
|||
@classmethod
|
||||
def now(cls):
|
||||
return mydatetime
|
||||
patcher = patch("rackclient.v1.syscall.default.pipe.datetime", FakeDateTime)
|
||||
patcher = patch("rackclient.lib.syscall.default.pipe.datetime", FakeDateTime)
|
||||
patcher.start()
|
||||
self.ins_redis.keys.side_effect = [[], ["data"]]
|
||||
self.ins_redis.hget.side_effect = ["read", "write"]
|
||||
|
@ -228,5 +231,5 @@ class PipeTest(utils.TestCase):
|
|||
self.assertFalse(pipe.Pipe.share("ppid", "pid"))
|
||||
|
||||
def test_NoDescriptor_str_(self):
|
||||
self.assertEquals("Descriptor Not Found", pipe.NoDescriptor().__str__())
|
||||
self.assertEquals("Descriptor Not Found", exceptions.NoDescriptor().__str__())
|
||||
|
||||
|
|
|
@ -13,12 +13,12 @@
|
|||
# limitations under the License.
|
||||
from mock import patch
|
||||
from rackclient.tests import utils
|
||||
from rackclient.v1.syscall.default import shm
|
||||
from rackclient import process_context
|
||||
from rackclient.lib.syscall.default import shm
|
||||
|
||||
PCTXT = process_context.PCTXT
|
||||
class ShmTest(utils.LibTestCase):
|
||||
|
||||
class ShmTest(utils.TestCase):
|
||||
def target_context(self):
|
||||
return "syscall.default.shm"
|
||||
|
||||
def setUp(self):
|
||||
super(ShmTest, self).setUp()
|
||||
|
|
|
@ -11,16 +11,17 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from mock import patch, Mock
|
||||
from rackclient import process_context
|
||||
from rackclient.tests import utils
|
||||
from rackclient.v1.syscall.default import signal
|
||||
import copy
|
||||
|
||||
PCTXT = process_context.PCTXT
|
||||
from mock import patch, Mock
|
||||
from rackclient.tests import utils
|
||||
from rackclient.lib.syscall.default import signal
|
||||
|
||||
|
||||
class SignalTest(utils.TestCase):
|
||||
class SignalTest(utils.LibTestCase):
|
||||
|
||||
def target_context(self):
|
||||
return "syscall.default.signal"
|
||||
|
||||
def setUp(self):
|
||||
super(SignalTest, self).setUp()
|
||||
|
@ -37,7 +38,7 @@ class SignalTest(utils.TestCase):
|
|||
|
||||
mock_websocket_websocketapp.\
|
||||
assert_called_with(url=s.url + '/receive',
|
||||
header=['PID: ' + PCTXT.pid],
|
||||
header=['PID: ' + self.mock_RACK_CTX.pid],
|
||||
on_message=s.on_message,
|
||||
on_error=s.on_error,
|
||||
on_close=s.on_close)
|
||||
|
@ -73,7 +74,7 @@ class SignalTest(utils.TestCase):
|
|||
|
||||
s = signal.SignalManager()
|
||||
on_msg_func = 'on_msg_func'
|
||||
PCTXT.pid = None
|
||||
self.mock_RACK_CTX.pid = None
|
||||
self.assertRaises(Exception, s.receive, on_msg_func)
|
||||
|
||||
def test_on_message(self):
|
||||
|
|
|
@ -11,39 +11,35 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from rackclient import process_context
|
||||
from rackclient.tests import utils
|
||||
from rackclient.v1 import processes
|
||||
from rackclient.v1.syscall.default import file
|
||||
from rackclient.v1.syscall.default import messaging
|
||||
from rackclient.v1.syscall.default import pipe
|
||||
from rackclient.v1.syscall.default import syscall
|
||||
|
||||
from rackclient.lib.syscall.default import messaging, file, syscall, pipe
|
||||
from mock import call
|
||||
from mock import Mock
|
||||
|
||||
PCTXT = process_context.PCTXT
|
||||
|
||||
class SyscallTest(utils.LibTestCase):
|
||||
|
||||
class SyscallTest(utils.TestCase):
|
||||
def target_context(self):
|
||||
return "syscall.default.syscall"
|
||||
|
||||
def setUp(self):
|
||||
super(SyscallTest, self).setUp()
|
||||
|
||||
def test_fork(self):
|
||||
def create_process(gid, ppid, **kwargs):
|
||||
count = PCTXT.client.processes.create.call_count
|
||||
count = self.mock_RACK_CTX.client.processes.create.call_count
|
||||
d = {'ppid': ppid,
|
||||
'pid': 'pid' + str(count),
|
||||
'gid': gid,
|
||||
'proxy_ip': PCTXT.proxy_ip}
|
||||
'proxy_ip': self.mock_RACK_CTX.proxy_ip}
|
||||
args = kwargs['args']
|
||||
args.update(d)
|
||||
kwargs.update(d)
|
||||
return_process = processes.Process(PCTXT.client, kwargs)
|
||||
return_process = processes.Process(self.mock_RACK_CTX.client, kwargs)
|
||||
return return_process
|
||||
|
||||
PCTXT.client.processes.create = Mock(side_effect=create_process)
|
||||
self.mock_RACK_CTX.client.processes.create = Mock(side_effect=create_process)
|
||||
# messaging mock
|
||||
mock_messaging = Mock()
|
||||
messaging.Messaging = Mock(return_value=mock_messaging)
|
||||
|
@ -74,28 +70,28 @@ class SyscallTest(utils.TestCase):
|
|||
expected_arg_list = [arg1, arg2, arg3]
|
||||
for process in process_list:
|
||||
self.assertTrue(process.args in expected_arg_list)
|
||||
self.assertEqual(process.ppid, PCTXT.pid)
|
||||
self.assertEqual(process.gid, PCTXT.gid)
|
||||
self.assertEqual(process.ppid, self.mock_RACK_CTX.pid)
|
||||
self.assertEqual(process.gid, self.mock_RACK_CTX.gid)
|
||||
expected_arg_list.remove(process.args)
|
||||
|
||||
def test_bulk_fork_check_connection_recoverable_error(self):
|
||||
# setup
|
||||
def create_process(gid, ppid, **kwargs):
|
||||
count = PCTXT.client.processes.create.call_count
|
||||
count = self.mock_RACK_CTX.client.processes.create.call_count
|
||||
if count == 2:
|
||||
raise Exception()
|
||||
d = {'ppid': ppid,
|
||||
'pid': 'pid' + str(count),
|
||||
'gid': gid,
|
||||
'proxy_ip': PCTXT.proxy_ip}
|
||||
'proxy_ip': self.mock_RACK_CTX.proxy_ip}
|
||||
args = kwargs['args']
|
||||
args.update(d)
|
||||
kwargs.update(d)
|
||||
return_process = processes.Process(PCTXT.client, kwargs)
|
||||
return_process = processes.Process(self.mock_RACK_CTX.client, kwargs)
|
||||
return return_process
|
||||
|
||||
PCTXT.client.processes.create = Mock(side_effect=create_process)
|
||||
PCTXT.client.processes.delete = Mock()
|
||||
self.mock_RACK_CTX.client.processes.create = Mock(side_effect=create_process)
|
||||
self.mock_RACK_CTX.client.processes.delete = Mock()
|
||||
|
||||
# messaging mock
|
||||
mock_messaging = Mock()
|
||||
|
@ -116,7 +112,7 @@ class SyscallTest(utils.TestCase):
|
|||
process_list = syscall.fork(arg_list)
|
||||
|
||||
# check
|
||||
PCTXT.client.processes.delete.assert_called_with(PCTXT.gid, 'pid1')
|
||||
self.mock_RACK_CTX.client.processes.delete.assert_called_with(self.mock_RACK_CTX.gid, 'pid1')
|
||||
expected_pipe_share = [call('pid', 'pid3'),
|
||||
call('pid', 'pid4'),
|
||||
call('pid', 'pid5')]
|
||||
|
@ -129,12 +125,12 @@ class SyscallTest(utils.TestCase):
|
|||
expected_arg_list = [arg1, arg2, arg3]
|
||||
for process in process_list:
|
||||
self.assertTrue(process.args in expected_arg_list)
|
||||
self.assertEqual(process.ppid, PCTXT.pid)
|
||||
self.assertEqual(process.gid, PCTXT.gid)
|
||||
self.assertEqual(process.ppid, self.mock_RACK_CTX.pid)
|
||||
self.assertEqual(process.gid, self.mock_RACK_CTX.gid)
|
||||
expected_arg_list.remove(process.args)
|
||||
|
||||
def test_bulk_fork_error_no_child_process_is_created(self):
|
||||
PCTXT.client.processes.create = Mock(side_effect=Exception)
|
||||
self.mock_RACK_CTX.client.processes.create = Mock(side_effect=Exception)
|
||||
# call fork
|
||||
arg1 = {'test': 'test1'}
|
||||
arg2 = {'test': 'test2'}
|
||||
|
@ -147,19 +143,19 @@ class SyscallTest(utils.TestCase):
|
|||
def test_check_connection_error_no_child_process_is_active(self):
|
||||
# setup
|
||||
def create_process(gid, ppid, **kwargs):
|
||||
count = PCTXT.client.processes.create.call_count
|
||||
count = self.mock_RACK_CTX.client.processes.create.call_count
|
||||
d = {'ppid': ppid,
|
||||
'pid': 'pid' + str(count),
|
||||
'gid': gid,
|
||||
'proxy_ip': PCTXT.proxy_ip}
|
||||
'proxy_ip': self.mock_RACK_CTX.proxy_ip}
|
||||
args = kwargs['args']
|
||||
args.update(d)
|
||||
kwargs.update(d)
|
||||
return_process = processes.Process(PCTXT.client, kwargs)
|
||||
return_process = processes.Process(self.mock_RACK_CTX.client, kwargs)
|
||||
return return_process
|
||||
|
||||
PCTXT.client.processes.create = Mock(side_effect=create_process)
|
||||
PCTXT.client.processes.delete = Mock()
|
||||
self.mock_RACK_CTX.client.processes.create = Mock(side_effect=create_process)
|
||||
self.mock_RACK_CTX.client.processes.delete = Mock()
|
||||
# messaging mock
|
||||
mock_messaging = Mock()
|
||||
messaging.Messaging = Mock(return_value=mock_messaging)
|
||||
|
@ -171,11 +167,11 @@ class SyscallTest(utils.TestCase):
|
|||
{'args': {'test': 'test2'}},
|
||||
{'args': {'test': 'test3'}}]
|
||||
self.assertRaises(Exception, syscall.fork, arg_list)
|
||||
expected_processes_delete = [call(PCTXT.gid, 'pid1'),
|
||||
call(PCTXT.gid, 'pid2'),
|
||||
call(PCTXT.gid, 'pid3')]
|
||||
expected_processes_delete = [call(self.mock_RACK_CTX.gid, 'pid1'),
|
||||
call(self.mock_RACK_CTX.gid, 'pid2'),
|
||||
call(self.mock_RACK_CTX.gid, 'pid3')]
|
||||
self.assertEqual(expected_processes_delete,
|
||||
PCTXT.client.processes.delete.call_args_list)
|
||||
self.mock_RACK_CTX.client.processes.delete.call_args_list)
|
||||
|
||||
def test_pipe_no_arg(self):
|
||||
pipe.Pipe = Mock()
|
||||
|
|
|
@ -1,486 +0,0 @@
|
|||
# Copyright (c) 2014 ITOCHU Techno-Solutions Corporation.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from ConfigParser import NoOptionError
|
||||
import StringIO
|
||||
import copy
|
||||
import fixtures
|
||||
import mock
|
||||
from mock import mock_open
|
||||
import os
|
||||
import re
|
||||
from testtools import matchers
|
||||
from rackclient import exceptions
|
||||
import rackclient.shell
|
||||
from rackclient.v1.proxy import ProxyManager
|
||||
from rackclient.tests.v1 import fakes
|
||||
from rackclient.tests import utils
|
||||
|
||||
|
||||
class BaseShellTest(utils.TestCase):
|
||||
|
||||
FAKE_ENV = {
|
||||
'RACK_URL': 'http://www.example.com:8088/v1',
|
||||
'RACK_GID': '11111111',
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
"""Run before each test."""
|
||||
super(BaseShellTest, self).setUp()
|
||||
|
||||
for var in self.FAKE_ENV:
|
||||
self.useFixture(fixtures.EnvironmentVariable(var,
|
||||
self.FAKE_ENV[var]))
|
||||
self.shell = rackclient.shell.RackShell()
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
'rackclient.client.get_client_class',
|
||||
lambda *_: fakes.FakeClient))
|
||||
|
||||
def assert_called(self, method, url, body=None, **kwargs):
|
||||
self.shell.cs.assert_called(method, url, body, **kwargs)
|
||||
|
||||
def assert_called_anytime(self, method, url, body=None):
|
||||
self.shell.cs.assert_called_anytime(method, url, body)
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=StringIO.StringIO)
|
||||
def run_command(self, cmd, mock_stdout):
|
||||
if isinstance(cmd, list):
|
||||
self.shell.main(cmd)
|
||||
else:
|
||||
self.shell.main(cmd.split())
|
||||
return mock_stdout.getvalue()
|
||||
|
||||
|
||||
class ShellTest(BaseShellTest):
|
||||
|
||||
def test_group_list(self):
|
||||
self.run_command('group-list')
|
||||
self.assert_called('GET', '/groups')
|
||||
|
||||
def test_group_show(self):
|
||||
self.run_command('group-show 11111111')
|
||||
self.assert_called('GET', '/groups/11111111', pos=-6)
|
||||
self.assert_called('GET', '/groups/11111111/keypairs', pos=-5)
|
||||
self.assert_called('GET', '/groups/11111111/securitygroups', pos=-4)
|
||||
self.assert_called('GET', '/groups/11111111/networks', pos=-3)
|
||||
self.assert_called('GET', '/groups/11111111/processes', pos=-2)
|
||||
self.assert_called('GET', '/groups/11111111/proxy', pos=-1)
|
||||
|
||||
@mock.patch.object(ProxyManager, 'get', side_effect=Exception())
|
||||
def test_group_show_no_proxy(self, mock_proxy_manager):
|
||||
stdout = self.run_command('group-show 11111111')
|
||||
required = '.*?^\|\s+proxy \(pid\)\s+\|\s+\|'
|
||||
self.assertThat(stdout,
|
||||
matchers.MatchesRegex(required, re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_group_create(self):
|
||||
self.run_command('group-create --description detail group1')
|
||||
self.assert_called('POST', '/groups')
|
||||
|
||||
def test_group_update(self):
|
||||
self.run_command('group-update --name group2 --description detail2 11111111')
|
||||
self.assert_called('PUT', '/groups/11111111')
|
||||
|
||||
def test_group_delete(self):
|
||||
self.run_command('group-delete 11111111')
|
||||
self.assert_called('DELETE', '/groups/11111111')
|
||||
|
||||
def test_keypair_list(self):
|
||||
self.run_command('keypair-list')
|
||||
self.assert_called('GET', '/groups/11111111/keypairs')
|
||||
|
||||
def test_keypair_show(self):
|
||||
self.run_command('keypair-show aaaaaaaa')
|
||||
self.assert_called('GET', '/groups/11111111/keypairs/aaaaaaaa')
|
||||
|
||||
def test_keypair_create(self):
|
||||
self.run_command('keypair-create --name keypair1 '
|
||||
'--is_default true')
|
||||
self.assert_called('POST', '/groups/11111111/keypairs')
|
||||
|
||||
def test_keypair_update(self):
|
||||
self.run_command('keypair-update --is_default false aaaaaaaa')
|
||||
self.assert_called('PUT', '/groups/11111111/keypairs/aaaaaaaa')
|
||||
|
||||
def test_keypair_delete(self):
|
||||
self.run_command('keypair-delete aaaaaaaa')
|
||||
self.assert_called('DELETE', '/groups/11111111/keypairs/aaaaaaaa')
|
||||
|
||||
def test_securitygroup_list(self):
|
||||
self.run_command('securitygroup-list')
|
||||
self.assert_called('GET', '/groups/11111111/securitygroups')
|
||||
|
||||
def test_securitygroup_show(self):
|
||||
self.run_command('securitygroup-show aaaaaaaa')
|
||||
self.assert_called('GET', '/groups/11111111/securitygroups/aaaaaaaa')
|
||||
|
||||
def test_securitygroup_create(self):
|
||||
self.run_command('securitygroup-create --name securitygroup1 '
|
||||
'--is_default true '
|
||||
'--rule protocol=tcp,port_range_max=80,'
|
||||
'port_range_min=80,remote_ip_prefix=10.0.0.0/24 '
|
||||
'--rule protocol=icmp,remote_ip_prefix=10.0.0.0/24')
|
||||
self.assert_called('POST', '/groups/11111111/securitygroups')
|
||||
|
||||
def test_securitygroup_update(self):
|
||||
self.run_command('securitygroup-update --is_default false aaaaaaaa')
|
||||
self.assert_called('PUT', '/groups/11111111/securitygroups/aaaaaaaa')
|
||||
|
||||
def test_securitygroup_delete(self):
|
||||
self.run_command('securitygroup-delete aaaaaaaa')
|
||||
self.assert_called('DELETE', '/groups/11111111/securitygroups/aaaaaaaa')
|
||||
|
||||
def test_network_list(self):
|
||||
self.run_command('network-list')
|
||||
self.assert_called('GET', '/groups/11111111/networks')
|
||||
|
||||
def test_network_show(self):
|
||||
self.run_command('network-show aaaaaaaa')
|
||||
self.assert_called('GET', '/groups/11111111/networks/aaaaaaaa')
|
||||
|
||||
def test_network_create(self):
|
||||
self.run_command('network-create --name network1 '
|
||||
'--is_admin true '
|
||||
'--gateway_ip 10.0.0.254 '
|
||||
'--dns_nameserver 8.8.8.8 '
|
||||
'--dns_nameserver 8.8.4.4 '
|
||||
'--ext_router_id rrrrrrrr '
|
||||
'10.0.0.0/24')
|
||||
self.assert_called('POST', '/groups/11111111/networks')
|
||||
|
||||
def test_network_delete(self):
|
||||
self.run_command('network-delete aaaaaaaa')
|
||||
self.assert_called('DELETE', '/groups/11111111/networks/aaaaaaaa')
|
||||
|
||||
def test_process_list(self):
|
||||
self.run_command('process-list')
|
||||
self.assert_called('GET', '/groups/11111111/processes')
|
||||
|
||||
def test_process_show(self):
|
||||
self.run_command('process-show aaaaaaaa')
|
||||
self.assert_called('GET', '/groups/11111111/processes/aaaaaaaa')
|
||||
|
||||
def test_process_create(self):
|
||||
test_userdata = os.path.join(os.path.dirname(__file__), 'test_userdata.txt')
|
||||
self.run_command('process-create --ppid aaaaaaaa '
|
||||
'--name process1 '
|
||||
'--nova_flavor_id yyyyyyyy '
|
||||
'--glance_image_id xxxxxxxx '
|
||||
'--keypair_id iiiiiiii '
|
||||
'--securitygroup_id jjjjjjjj '
|
||||
'--securitygroup_id kkkkkkkk '
|
||||
'--userdata %s '
|
||||
'--args key1=value1,key2=value2' % test_userdata)
|
||||
self.assert_called('POST', '/groups/11111111/processes')
|
||||
|
||||
def test_process_create_with_no_option(self):
|
||||
self.run_command('process-create')
|
||||
self.assert_called('POST', '/groups/11111111/processes')
|
||||
|
||||
def test_process_could_not_open_userdata_file(self):
|
||||
try:
|
||||
self.run_command('process-create --ppid aaaaaaaa '
|
||||
'--userdata not_exists.txt')
|
||||
except exceptions.CommandError as e:
|
||||
required = ".*?^Can't open 'not_exists.txt'"
|
||||
self.assertThat(e.message,
|
||||
matchers.MatchesRegex(required, re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_process_with_args_file(self):
|
||||
test_args = os.path.join(os.path.dirname(__file__), 'test_args.txt')
|
||||
self.run_command('process-create --ppid aaaaaaaa '
|
||||
'--args %s' % test_args)
|
||||
self.assert_called('POST', '/groups/11111111/processes')
|
||||
|
||||
@mock.patch('__builtin__.open', side_effect=IOError())
|
||||
def test_process_could_not_open_args_file(self, m_open):
|
||||
try:
|
||||
test_args = os.path.join(os.path.dirname(__file__), 'test_args.txt')
|
||||
self.run_command('process-create --ppid aaaaaaaa '
|
||||
'--args %s' % test_args)
|
||||
except exceptions.CommandError as e:
|
||||
required = ".*?^Can't open '.*?rackclient/tests/v1/test_args.txt'"
|
||||
self.assertThat(str(e.message),
|
||||
matchers.MatchesRegex(required, re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_process_invalid_args_file(self):
|
||||
invalid_args = os.path.join(os.path.dirname(__file__), 'test_invalid_args.txt')
|
||||
try:
|
||||
self.run_command('process-create --ppid aaaaaaaa '
|
||||
'--args %s' % invalid_args)
|
||||
except exceptions.CommandError as e:
|
||||
required = ('.*?rackclient/tests/v1/test_invalid_args.txt '
|
||||
'is not the format of key=value lines')
|
||||
self.assertThat(e.message,
|
||||
matchers.MatchesRegex(required, re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_process_invalid_args(self):
|
||||
try:
|
||||
self.run_command('process-create --ppid aaaaaaaa '
|
||||
'--args key1value1')
|
||||
except exceptions.CommandError as e:
|
||||
required = '.*?^\'key1value1\' is not in the format of key=value'
|
||||
self.assertThat(str(e.message),
|
||||
matchers.MatchesRegex(required, re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_process_update(self):
|
||||
self.run_command('process-update --app_status ACTIVE aaaaaaaa')
|
||||
self.assert_called('PUT', '/groups/11111111/processes/aaaaaaaa')
|
||||
|
||||
def test_process_delete(self):
|
||||
self.run_command('process-delete aaaaaaaa')
|
||||
self.assert_called('DELETE', '/groups/11111111/processes/aaaaaaaa')
|
||||
|
||||
def test_proxy_show(self):
|
||||
self.run_command('proxy-show')
|
||||
self.assert_called('GET', '/groups/11111111/proxy')
|
||||
|
||||
def test_proxy_create(self):
|
||||
test_userdata = os.path.join(os.path.dirname(__file__), 'test_userdata.txt')
|
||||
self.run_command('proxy-create '
|
||||
'--name proxy '
|
||||
'--nova_flavor_id yyyyyyyy '
|
||||
'--glance_image_id xxxxxxxx '
|
||||
'--keypair_id iiiiiiii '
|
||||
'--securitygroup_id jjjjjjjj '
|
||||
'--securitygroup_id kkkkkkkk '
|
||||
'--userdata %s '
|
||||
'--args key1=value1,key2=value2' % test_userdata)
|
||||
self.assert_called('POST', '/groups/11111111/proxy')
|
||||
|
||||
def test_proxy_create_with_no_option(self):
|
||||
self.run_command('proxy-create')
|
||||
self.assert_called('POST', '/groups/11111111/proxy')
|
||||
|
||||
def test_procexy_could_not_open_userdata_file(self):
|
||||
try:
|
||||
self.run_command('proxy-create '
|
||||
'--userdata not_exists.txt')
|
||||
except exceptions.CommandError as e:
|
||||
required = ".*?^Can't open 'not_exists.txt'"
|
||||
self.assertThat(e.message,
|
||||
matchers.MatchesRegex(required, re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_proxy_with_args_file(self):
|
||||
test_args = os.path.join(os.path.dirname(__file__), 'test_args.txt')
|
||||
self.run_command('proxy-create '
|
||||
'--args %s' % test_args)
|
||||
self.assert_called('POST', '/groups/11111111/proxy')
|
||||
|
||||
@mock.patch('__builtin__.open', side_effect=IOError())
|
||||
def test_proxy_could_not_open_args_file(self, m_open):
|
||||
try:
|
||||
test_args = os.path.join(os.path.dirname(__file__), 'test_args.txt')
|
||||
self.run_command('proxy-create '
|
||||
'--args %s' % test_args)
|
||||
except exceptions.CommandError as e:
|
||||
required = ".*?^Can't open '.*?rackclient/tests/v1/test_args.txt'"
|
||||
self.assertThat(str(e.message),
|
||||
matchers.MatchesRegex(required, re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_proxy_invalid_args_file(self):
|
||||
invalid_args = os.path.join(os.path.dirname(__file__), 'test_invalid_args.txt')
|
||||
try:
|
||||
self.run_command('proxy-create '
|
||||
'--args %s' % invalid_args)
|
||||
except exceptions.CommandError as e:
|
||||
required = ('.*?rackclient/tests/v1/test_invalid_args.txt '
|
||||
'is not the format of key=value lines')
|
||||
self.assertThat(e.message,
|
||||
matchers.MatchesRegex(required, re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_proxy_invalid_args(self):
|
||||
try:
|
||||
self.run_command('proxy-create '
|
||||
'--args key1value1')
|
||||
except exceptions.CommandError as e:
|
||||
required = '.*?^\'key1value1\' is not in the format of key=value'
|
||||
self.assertThat(str(e.message),
|
||||
matchers.MatchesRegex(required, re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_proxy_update(self):
|
||||
self.run_command('proxy-update --app_status ACTIVE '
|
||||
'--shm_endpoint shm_endpoint '
|
||||
'--ipc_endpoint ipc_endpoint '
|
||||
'--fs_endpoint fs_endpoint')
|
||||
self.assert_called('PUT', '/groups/11111111/proxy')
|
||||
|
||||
|
||||
class ShellGroupInitTest(BaseShellTest):
|
||||
|
||||
CONFIG = {
|
||||
'group': {
|
||||
'name': 'group1',
|
||||
'description': 'This is group1'
|
||||
},
|
||||
'keypair': {
|
||||
'name': 'keypair1',
|
||||
'is_default': 't'
|
||||
},
|
||||
'securitygroup': {
|
||||
'name': 'securitygroup1',
|
||||
'is_default': 't',
|
||||
'rules': 'protocol=tcp,port_range_max=80,'
|
||||
'port_range_min=80,remote_ip_prefix=10.0.0.0/24 '
|
||||
'protocol=icmp,remote_ip_prefix=10.0.0.0/24'
|
||||
},
|
||||
'network': {
|
||||
'cidr': '10.0.0.0/24',
|
||||
'name': 'network1',
|
||||
'is_admin': 't',
|
||||
'gateway_ip': '10.0.0.254',
|
||||
'dns_nameservers': '8.8.8.8 8.8.4.4',
|
||||
'ext_router_id': 'rrrrrrrr'
|
||||
},
|
||||
'proxy': {
|
||||
'name': 'proxy',
|
||||
'nova_flavor_id': 'yyyyyyyy',
|
||||
'glance_image_id': 'xxxxxxxx',
|
||||
'args': 'key1=value1,key2=value2'
|
||||
}
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
super(ShellGroupInitTest, self).setUp()
|
||||
self.config = copy.deepcopy(self.CONFIG)
|
||||
self.patcher = mock.patch('rackclient.v1.shell.ConfigParser')
|
||||
self.mock_config = self.patcher.start()
|
||||
|
||||
def tearDown(self):
|
||||
super(BaseShellTest, self).tearDown()
|
||||
self.patcher.stop()
|
||||
|
||||
def _fake_get(self, section, key):
|
||||
try:
|
||||
return self.config[section][key]
|
||||
except KeyError:
|
||||
raise NoOptionError(key, section)
|
||||
|
||||
def test_group_init(self):
|
||||
test_userdata = os.path.join(os.path.dirname(__file__),
|
||||
'test_userdata.txt')
|
||||
self.config['proxy']['userdata'] = test_userdata
|
||||
self.mock_config.return_value.get = self._fake_get
|
||||
self.run_command('group-init /path/to/group.conf')
|
||||
|
||||
def test_group_init_with_required(self):
|
||||
self.config['group'].pop('description')
|
||||
self.config['keypair'].pop('name')
|
||||
self.config['keypair'].pop('is_default')
|
||||
self.config['securitygroup'].pop('name')
|
||||
self.config['securitygroup'].pop('is_default')
|
||||
self.config['securitygroup'].pop('rules')
|
||||
self.config['network'].pop('name')
|
||||
self.config['network'].pop('is_admin')
|
||||
self.config['network'].pop('gateway_ip')
|
||||
self.config['network'].pop('dns_nameservers')
|
||||
self.config['network'].pop('ext_router_id')
|
||||
self.config['proxy'].pop('name')
|
||||
self.config['proxy'].pop('args')
|
||||
self.mock_config.return_value.get = self._fake_get
|
||||
self.run_command('group-init /path/to/group.conf')
|
||||
|
||||
def test_group_init_without_group_name(self):
|
||||
self.config['group'].pop('name')
|
||||
self.mock_config.return_value.get = self._fake_get
|
||||
|
||||
try:
|
||||
self.run_command('group-init /path/to/group.conf')
|
||||
except exceptions.CommandError as e:
|
||||
required = '.*?^Group name is required.'
|
||||
self.assertThat(
|
||||
str(e.message),
|
||||
matchers.MatchesRegex(required,
|
||||
re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_group_init_invalid_securitygroup_rules(self):
|
||||
self.config['securitygroup']['rules'] = 'invalid'
|
||||
self.mock_config.return_value.get = self._fake_get
|
||||
|
||||
try:
|
||||
self.run_command('group-init /path/to/group.conf')
|
||||
except exceptions.CommandError as e:
|
||||
required = ('.*?^Could not create a securitygroup: '
|
||||
'securitygroup rules are not valid formart: '
|
||||
'\'.*\' is not in the format of key=value')
|
||||
self.assertThat(
|
||||
str(e.message),
|
||||
matchers.MatchesRegex(required,
|
||||
re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_group_init_without_network_cidr(self):
|
||||
self.config['network'].pop('cidr')
|
||||
self.mock_config.return_value.get = self._fake_get
|
||||
|
||||
try:
|
||||
self.run_command('group-init /path/to/group.conf')
|
||||
except exceptions.CommandError as e:
|
||||
required = '.*?^Network cidr is required.'
|
||||
self.assertThat(
|
||||
str(e.message),
|
||||
matchers.MatchesRegex(required,
|
||||
re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_group_init_without_proxy_nova_flavor_id(self):
|
||||
self.config['proxy'].pop('nova_flavor_id')
|
||||
self.mock_config.return_value.get = self._fake_get
|
||||
|
||||
try:
|
||||
self.run_command('group-init /path/to/group.conf')
|
||||
except exceptions.CommandError as e:
|
||||
required = '.*?^Flavor id is required.'
|
||||
self.assertThat(
|
||||
str(e.message),
|
||||
matchers.MatchesRegex(required,
|
||||
re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_group_init_without_proxy_glance_image_id(self):
|
||||
self.config['proxy'].pop('glance_image_id')
|
||||
self.mock_config.return_value.get = self._fake_get
|
||||
|
||||
try:
|
||||
self.run_command('group-init /path/to/group.conf')
|
||||
except exceptions.CommandError as e:
|
||||
required = '.*?^Image id is required.'
|
||||
self.assertThat(
|
||||
str(e.message),
|
||||
matchers.MatchesRegex(required,
|
||||
re.DOTALL | re.MULTILINE))
|
||||
|
||||
@mock.patch('__builtin__.open', side_effect=IOError())
|
||||
def test_group_init_could_not_open_userdata(self, m_open):
|
||||
self.config['proxy']['userdata'] = 'fake_userdata.txt'
|
||||
self.mock_config.return_value.get = self._fake_get
|
||||
|
||||
try:
|
||||
self.run_command('group-init /path/to/group.conf')
|
||||
except exceptions.CommandError as e:
|
||||
required = '.*?^Can\'t open fake_userdata.txt.'
|
||||
self.assertThat(
|
||||
str(e.message),
|
||||
matchers.MatchesRegex(required,
|
||||
re.DOTALL | re.MULTILINE))
|
||||
|
||||
def test_group_init_invalid_args(self):
|
||||
self.config['proxy']['args'] = 'key1:value1'
|
||||
self.mock_config.return_value.get = self._fake_get
|
||||
|
||||
try:
|
||||
self.run_command('group-init /path/to/group.conf')
|
||||
except exceptions.CommandError as e:
|
||||
required = ('.*?^\'key1:value1\' is not '
|
||||
'in the format of key=value')
|
||||
self.assertThat(
|
||||
str(e.message),
|
||||
matchers.MatchesRegex(required,
|
||||
re.DOTALL | re.MULTILINE))
|
|
@ -11,26 +11,24 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from rackclient import process_context
|
||||
from rackclient.v1.syscall.default import messaging
|
||||
from rackclient import exceptions
|
||||
|
||||
PCTXT = process_context.PCTXT
|
||||
import argparse
|
||||
|
||||
|
||||
def _is_exist():
|
||||
def keyvalue_to_dict(string):
|
||||
"""
|
||||
Return a dict made from comma separated key-value strings
|
||||
|
||||
:param string: comma separated key-value pairs
|
||||
like 'key1=value1,key2=value2'
|
||||
:return: dict
|
||||
"""
|
||||
try:
|
||||
PCTXT.client.processes.get(PCTXT.gid, PCTXT.pid)
|
||||
except exceptions.NotFound:
|
||||
msg = "This process is not recognized by RACK"
|
||||
raise exceptions.InvalidProcessError(msg)
|
||||
|
||||
|
||||
def init():
|
||||
try:
|
||||
process_context.init()
|
||||
_is_exist()
|
||||
messaging.init()
|
||||
except Exception as e:
|
||||
msg = "Failed to initialize the process: %s." % e.message
|
||||
raise exceptions.ProcessInitError(msg)
|
||||
d = {}
|
||||
pairs = string.split(',')
|
||||
for pair in pairs:
|
||||
(k, v) = pair.split('=', 1)
|
||||
d.update({k: v})
|
||||
return d
|
||||
except ValueError:
|
||||
msg = "%r is not in the format of key=value" % string
|
||||
raise argparse.ArgumentTypeError(msg)
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright (c) 2014 ITOCHU Techno-Solutions Corporation.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
|
@ -0,0 +1,338 @@
|
|||
# Copyright (c) 2014 ITOCHU Techno-Solutions Corporation.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import argparse
|
||||
import os
|
||||
|
||||
from ConfigParser import ConfigParser
|
||||
from ConfigParser import NoOptionError
|
||||
|
||||
from cliff.command import Command
|
||||
from cliff.lister import Lister
|
||||
from cliff.show import ShowOne
|
||||
|
||||
from rackclient import client
|
||||
from rackclient import exceptions
|
||||
from rackclient import utils
|
||||
|
||||
|
||||
def _make_print_data(gid, name, description, user_id, project_id,
|
||||
status, keypairs=None, securitygroups=None,
|
||||
networks=None, proxy=None, processes=None):
|
||||
columns = ['gid', 'name', 'description', 'user_id', 'project_id', 'status']
|
||||
data = [gid, name, description, user_id, project_id, status]
|
||||
|
||||
if keypairs is not None:
|
||||
columns.append('keypairs')
|
||||
data.append(keypairs)
|
||||
|
||||
if securitygroups is not None:
|
||||
columns.append('securitygroups')
|
||||
data.append(securitygroups)
|
||||
|
||||
if networks is not None:
|
||||
columns.append('networks')
|
||||
data.append(networks)
|
||||
|
||||
if proxy is not None:
|
||||
columns.append('proxy (pid)')
|
||||
data.append(proxy)
|
||||
|
||||
if processes is not None:
|
||||
columns.append('processes (pid)')
|
||||
data.append(processes)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
class ListGroups(Lister):
|
||||
"""
|
||||
Print a list of all groups.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(ListGroups, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
groups = self.client.groups.list()
|
||||
return (
|
||||
('gid', 'name', 'description', 'status'),
|
||||
((g.gid, g.name, g.description, g.status) for g in groups)
|
||||
)
|
||||
|
||||
|
||||
class ShowGroup(ShowOne):
|
||||
"""
|
||||
Show details about the given group.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(ShowGroup, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowGroup, self).get_parser(prog_name)
|
||||
parser.add_argument('gid', metavar='<gid>',
|
||||
default=os.environ.get('RACK_GID'),
|
||||
help="Group id")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
group = self.client.groups.get(parsed_args.gid)
|
||||
keypairs = self.client.keypairs.list(parsed_args.gid)
|
||||
securitygroups = self.client.securitygroups.list(parsed_args.gid)
|
||||
networks = self.client.networks.list(parsed_args.gid)
|
||||
processes = self.client.processes.list(parsed_args.gid)
|
||||
try:
|
||||
proxy = self.client.proxy.get(parsed_args.gid)
|
||||
except Exception:
|
||||
proxy = None
|
||||
|
||||
return _make_print_data(
|
||||
group.gid,
|
||||
group.name,
|
||||
group.description,
|
||||
group.user_id,
|
||||
group.project_id,
|
||||
group.status,
|
||||
','.join([k.keypair_id for k in keypairs]),
|
||||
','.join([s.securitygroup_id for s in securitygroups]),
|
||||
','.join([n.network_id for n in networks]),
|
||||
','.join([p.pid for p in processes]),
|
||||
proxy.pid if proxy else ''
|
||||
)
|
||||
|
||||
|
||||
class CreateGroup(ShowOne):
|
||||
"""
|
||||
Create a new group.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(CreateGroup, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateGroup, self).get_parser(prog_name)
|
||||
parser.add_argument('name', metavar='<name>',
|
||||
help="Name of the new group")
|
||||
parser.add_argument('--description', metavar='<description>',
|
||||
help="Details of the new group")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
group = self.client.groups.create(parsed_args.name, parsed_args.description)
|
||||
return _make_print_data(
|
||||
group.gid,
|
||||
group.name,
|
||||
group.description,
|
||||
group.user_id,
|
||||
group.project_id,
|
||||
group.status
|
||||
)
|
||||
|
||||
|
||||
class UpdateGroup(ShowOne):
|
||||
"""
|
||||
Update the specified group.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(UpdateGroup, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UpdateGroup, self).get_parser(prog_name)
|
||||
parser.add_argument('gid', metavar='<gid>',
|
||||
help="Group id")
|
||||
parser.add_argument('--name', metavar='<name>',
|
||||
help="Name of the group")
|
||||
parser.add_argument('--description', metavar='<description>',
|
||||
help="Details of the group")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
group = self.client.groups.update(parsed_args.gid,
|
||||
parsed_args.name,
|
||||
parsed_args.description)
|
||||
return _make_print_data(
|
||||
group.gid,
|
||||
group.name,
|
||||
group.description,
|
||||
group.user_id,
|
||||
group.project_id,
|
||||
group.status
|
||||
)
|
||||
|
||||
|
||||
class DeleteGroup(Command):
|
||||
"""
|
||||
Delete the specified group.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(DeleteGroup, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteGroup, self).get_parser(prog_name)
|
||||
parser.add_argument('gid', metavar='<gid>',
|
||||
help="Group id")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
group = self.client.groups.delete(parsed_args.gid)
|
||||
|
||||
|
||||
class InitGroup(ShowOne):
|
||||
"""
|
||||
Create a group, a keypair, a security group, a network and
|
||||
a rack-proxy based on the specified configuration file.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(InitGroup, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(InitGroup, self).get_parser(prog_name)
|
||||
parser.add_argument('config', metavar='<config-file>',
|
||||
help="Configuration file including parameters of the new group")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
config = ConfigParser()
|
||||
config.read(parsed_args.config)
|
||||
|
||||
group_name = None
|
||||
group_description = None
|
||||
keypair_name = None
|
||||
keypair_is_default = True
|
||||
securitygroup_name = None
|
||||
securitygroup_is_default = True
|
||||
securitygroup_rules= []
|
||||
network_cidr = None
|
||||
network_name = None
|
||||
network_is_admin = True
|
||||
network_gateway_ip = None
|
||||
network_dns_nameservers = []
|
||||
network_ext_router_id = None
|
||||
proxy_name = None
|
||||
proxy_flavor = None
|
||||
proxy_image = None
|
||||
|
||||
try:
|
||||
group_name = config.get('group', 'name')
|
||||
except NoOptionError:
|
||||
raise exceptions.CommandError("Group name is required.")
|
||||
|
||||
try:
|
||||
network_cidr = config.get('network', 'cidr')
|
||||
except NoOptionError:
|
||||
raise exceptions.CommandError("Network cidr is required.")
|
||||
|
||||
try:
|
||||
securitygroup_rules = config.get('securitygroup', 'rules').split()
|
||||
securitygroup_rules = \
|
||||
[utils.keyvalue_to_dict(r) for r in securitygroup_rules]
|
||||
except argparse.ArgumentTypeError:
|
||||
raise exceptions.CommandError((
|
||||
"Could not create a securitygroup: "
|
||||
"securitygroup rules are not valid formart"))
|
||||
|
||||
try:
|
||||
network_ext_router_id = config.get('network', 'ext_router_id')
|
||||
except NoOptionError:
|
||||
raise exceptions.CommandError("Router ID is required.")
|
||||
|
||||
try:
|
||||
proxy_flavor = config.get('proxy', 'nova_flavor_id')
|
||||
except NoOptionError:
|
||||
raise exceptions.CommandError("Flavor ID is required.")
|
||||
|
||||
try:
|
||||
proxy_image = config.get('proxy', 'glance_image_id')
|
||||
except NoOptionError:
|
||||
raise exceptions.CommandError("Image ID is required.")
|
||||
|
||||
try:
|
||||
group_description = config.get('group', 'description')
|
||||
keypair_name = config.get('keypair', 'name')
|
||||
keypair_is_default = config.get('keypair', 'is_default')
|
||||
securitygroup_name = config.get('securitygroup', 'name')
|
||||
securitygroup_is_default = config.get('securitygroup', 'is_default')
|
||||
network_name = config.get('network', 'name')
|
||||
network_is_admin = config.get('network', 'is_admin')
|
||||
network_gateway_ip = config.get('network', 'gateway_ip')
|
||||
network_dns_nameservers = config.get('network', 'dns_nameservers').split()
|
||||
except NoOptionError:
|
||||
pass
|
||||
|
||||
group = self.client.groups.create(group_name, group_description)
|
||||
keypair = self.client.keypairs.create(group.gid, keypair_name,
|
||||
keypair_is_default)
|
||||
securitygroup = self.client.securitygroups.create(
|
||||
group.gid,
|
||||
securitygroup_name,
|
||||
securitygroup_is_default,
|
||||
securitygroup_rules)
|
||||
network = self.client.networks.create(
|
||||
group.gid, network_cidr, network_name,
|
||||
network_is_admin, network_gateway_ip,
|
||||
network_dns_nameservers,
|
||||
network_ext_router_id)
|
||||
proxy = self.client.proxy.create(
|
||||
group.gid, name=proxy_name,
|
||||
nova_flavor_id=proxy_flavor,
|
||||
glance_image_id=proxy_image,
|
||||
keypair_id=keypair.keypair_id,
|
||||
securitygroup_ids=[securitygroup.securitygroup_id])
|
||||
|
||||
columns = ['gid', 'keypair_id', 'securitygroup_id', 'network_id',
|
||||
'proxy_pid', 'proxy_name']
|
||||
data = [group.gid, keypair.keypair_id, securitygroup.securitygroup_id,
|
||||
network.network_id, proxy.pid, proxy.name]
|
||||
|
||||
return columns, data
|
||||
|
|
@ -0,0 +1,199 @@
|
|||
# Copyright (c) 2014 ITOCHU Techno-Solutions Corporation.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import argparse
|
||||
|
||||
from cliff.command import Command
|
||||
from cliff.lister import Lister
|
||||
from cliff.show import ShowOne
|
||||
|
||||
from rackclient import client
|
||||
|
||||
|
||||
def _make_print_data(keypair_id, name, nova_keypair_id, is_default, private_key,
|
||||
gid, user_id, project_id, status=None):
|
||||
columns = ['keypair_id', 'name', 'nova_keypair_id', 'is_default',
|
||||
'private_key', 'gid', 'user_id', 'project_id']
|
||||
data = [keypair_id, name, nova_keypair_id, is_default,
|
||||
private_key, gid, user_id, project_id]
|
||||
|
||||
if status is not None:
|
||||
columns.append('status')
|
||||
data.append(status)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
class ListKeypairs(Lister):
|
||||
"""
|
||||
Print a list of all keypairs in the specified group.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(ListKeypairs, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
keypairs = self.client.keypairs.list(self.gid)
|
||||
return (
|
||||
('keypair_id', 'name', 'is_default', 'status'),
|
||||
((k.keypair_id, k.name, k.is_default, k.status) for k in keypairs)
|
||||
)
|
||||
|
||||
|
||||
class ShowKeypair(ShowOne):
|
||||
"""
|
||||
Show details about the given keypair.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(ShowKeypair, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowKeypair, self).get_parser(prog_name)
|
||||
parser.add_argument('keypair_id', metavar='<keypair-id>',
|
||||
help="Keypair ID")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
keypair = self.client.keypairs.get(self.gid,
|
||||
parsed_args.keypair_id)
|
||||
return _make_print_data(
|
||||
keypair.keypair_id,
|
||||
keypair.name,
|
||||
keypair.nova_keypair_id,
|
||||
keypair.is_default,
|
||||
keypair.private_key,
|
||||
keypair.gid,
|
||||
keypair.user_id,
|
||||
keypair.project_id,
|
||||
keypair.status
|
||||
)
|
||||
|
||||
|
||||
class CreateKeypair(ShowOne):
|
||||
"""
|
||||
Create a new keypair.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(CreateKeypair, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateKeypair, self).get_parser(prog_name)
|
||||
parser.add_argument('--name', metavar='<name>',
|
||||
help="Name of the new keypair")
|
||||
parser.add_argument('--is-default', metavar='<true/false>',
|
||||
default=False,
|
||||
help="Defaults to the default keypair of the group")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
keypair = self.client.keypairs.create(self.gid, parsed_args.name,
|
||||
parsed_args.is_default)
|
||||
return _make_print_data(
|
||||
keypair.keypair_id,
|
||||
keypair.name,
|
||||
keypair.nova_keypair_id,
|
||||
keypair.is_default,
|
||||
keypair.private_key,
|
||||
keypair.gid,
|
||||
keypair.user_id,
|
||||
keypair.project_id,
|
||||
)
|
||||
|
||||
|
||||
class UpdateKeypair(ShowOne):
|
||||
"""
|
||||
Update the specified keypair.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(UpdateKeypair, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UpdateKeypair, self).get_parser(prog_name)
|
||||
parser.add_argument('keypair_id', metavar='<keypair-id>',
|
||||
help="Keypair ID")
|
||||
parser.add_argument('--is-default', metavar='<true/false>',
|
||||
required=True,
|
||||
help="Defaults to the default keypair of the group")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
keypair = self.client.keypairs.update(self.gid,
|
||||
parsed_args.keypair_id,
|
||||
parsed_args.is_default)
|
||||
return _make_print_data(
|
||||
keypair.keypair_id,
|
||||
keypair.name,
|
||||
keypair.nova_keypair_id,
|
||||
keypair.is_default,
|
||||
keypair.private_key,
|
||||
keypair.gid,
|
||||
keypair.user_id,
|
||||
keypair.project_id,
|
||||
)
|
||||
|
||||
|
||||
class DeleteKeypair(Command):
|
||||
"""
|
||||
Delete the specified keypair.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(DeleteKeypair, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteKeypair, self).get_parser(prog_name)
|
||||
parser.add_argument('keypair_id', metavar='<keypair-id>',
|
||||
help="Keypair ID")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
keypair = self.client.keypairs.delete(self.gid, parsed_args.keypair_id)
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
# Copyright (c) 2014 ITOCHU Techno-Solutions Corporation.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import argparse
|
||||
|
||||
from cliff.show import ShowOne
|
||||
|
||||
from rackclient import client
|
||||
|
||||
|
||||
class Montecarlo(ShowOne):
|
||||
"""
|
||||
The application to approximate the circular constant
|
||||
with the Monte Carlo method
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(Montecarlo, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Montecarlo, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument('--msg_limit_time', metavar='<integer>',
|
||||
default=300, type=int,
|
||||
help="Parent waits for notifications of "
|
||||
"preparation completion from children "
|
||||
"until the timer reaches to msg_limit_time "
|
||||
"seconds")
|
||||
parser.add_argument('--noterm', metavar='<true/false>',
|
||||
default=False,
|
||||
help="(Intended for debugging) "
|
||||
"If true, all processes won't be deleted")
|
||||
parser.add_argument('--image', metavar='<image-id>',
|
||||
required=True,
|
||||
help="(Required) ID of the montecarlo image")
|
||||
parser.add_argument('--flavor', metavar='<flavor-id>',
|
||||
required=True,
|
||||
help="(Required) ID of a flavor")
|
||||
parser.add_argument('--trials', metavar='<integer>',
|
||||
required=True, type=int,
|
||||
help="(Required) The number of trials in a "
|
||||
"simulation")
|
||||
parser.add_argument('--workers', metavar='<integer>',
|
||||
required=True, type=int,
|
||||
help="(Required) The number of workers that "
|
||||
"will be launched")
|
||||
parser.add_argument('--stdout', metavar='</file/path>',
|
||||
required=True,
|
||||
help="(Required) File path on Swift to output "
|
||||
"the simulation report to")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
options = {
|
||||
"trials": parsed_args.trials,
|
||||
"workers": parsed_args.workers,
|
||||
"stdout": parsed_args.stdout,
|
||||
"msg_limit_time": parsed_args.msg_limit_time,
|
||||
"noterm": parsed_args.noterm
|
||||
}
|
||||
|
||||
process = self.client.processes.create(
|
||||
self.gid, name="montecarlo",
|
||||
nova_flavor_id=parsed_args.flavor,
|
||||
glance_image_id=parsed_args.image,
|
||||
args=options)
|
||||
|
||||
process_args = process.args
|
||||
process_args.pop('gid')
|
||||
process_args.pop('pid')
|
||||
process_args.pop('ppid', None)
|
||||
process_args.pop('proxy_ip', None)
|
||||
process_args.pop('rackapi_ip', None)
|
||||
|
||||
cmd = process.name
|
||||
for k, v in sorted(process_args.items()):
|
||||
cmd += ' --' + k + ' ' + v
|
||||
|
||||
columns = ['pid', 'ppid', 'cmd']
|
||||
data = [process.pid, process.ppid, cmd]
|
||||
|
||||
return columns, data
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
# Copyright (c) 2014 ITOCHU Techno-Solutions Corporation.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import argparse
|
||||
|
||||
from cliff.command import Command
|
||||
from cliff.lister import Lister
|
||||
from cliff.show import ShowOne
|
||||
|
||||
from rackclient import client
|
||||
from rackclient import exceptions
|
||||
|
||||
|
||||
def _make_print_data(network_id, name, neutron_network_id, is_admin,
|
||||
cidr, ext_router_id, gid, user_id, project_id,
|
||||
status=None):
|
||||
columns = ['network_id', 'name', 'neutron_network_id', 'is_admin',
|
||||
'cidr', 'ext_router_id', 'gid', 'user_id', 'project_id']
|
||||
data = [network_id, name, neutron_network_id, is_admin,
|
||||
cidr, ext_router_id, gid, user_id, project_id]
|
||||
|
||||
if status is not None:
|
||||
columns.append('status')
|
||||
data.append(status)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
class ListNetworks(Lister):
|
||||
"""
|
||||
Print a list of all networks in the specified group.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(ListNetworks, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
networks = self.client.networks.list(self.gid)
|
||||
return (
|
||||
('network_id', 'name', 'is_admin', 'status'),
|
||||
((n.network_id, n.name, n.is_admin, n.status) for n in networks)
|
||||
)
|
||||
|
||||
|
||||
class ShowNetwork(ShowOne):
|
||||
"""
|
||||
Show details about the given network group.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(ShowNetwork, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowNetwork, self).get_parser(prog_name)
|
||||
parser.add_argument('network_id', metavar='<network-id>',
|
||||
help="Network ID")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
network = self.client.networks.get(self.gid,
|
||||
parsed_args.network_id)
|
||||
return _make_print_data(
|
||||
network.network_id,
|
||||
network.name,
|
||||
network.neutron_network_id,
|
||||
network.is_admin,
|
||||
network.cidr,
|
||||
network.ext_router_id,
|
||||
network.gid,
|
||||
network.user_id,
|
||||
network.project_id,
|
||||
network.status,
|
||||
)
|
||||
|
||||
|
||||
class CreateNetwork(ShowOne):
|
||||
"""
|
||||
Create a new securitygroup.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(CreateNetwork, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateNetwork, self).get_parser(prog_name)
|
||||
parser.add_argument('cidr', metavar='<cidr>',
|
||||
help="Cidr of the new network")
|
||||
parser.add_argument('--name', metavar='<name>',
|
||||
help="Name of the new securitygroup")
|
||||
parser.add_argument('--is-admin', metavar='<true/false>',
|
||||
default=False,
|
||||
help="")
|
||||
parser.add_argument('--gateway-ip', metavar='<x.x.x.x>',
|
||||
help="Gateway ip address of the new network")
|
||||
parser.add_argument('--dns-nameserver', metavar='<x.x.x.x>',
|
||||
dest='dns_nameservers', action='append',
|
||||
help="DNS server for the new network (Can be repeated)")
|
||||
parser.add_argument('--ext-router-id', metavar='<router-id>',
|
||||
help="Router id the new network connects to")
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
network = self.client.networks.create(self.gid,
|
||||
parsed_args.cidr,
|
||||
parsed_args.name,
|
||||
parsed_args.is_admin,
|
||||
parsed_args.gateway_ip,
|
||||
parsed_args.dns_nameservers,
|
||||
parsed_args.ext_router_id)
|
||||
return _make_print_data(
|
||||
network.network_id,
|
||||
network.name,
|
||||
network.neutron_network_id,
|
||||
network.is_admin,
|
||||
network.cidr,
|
||||
network.ext_router_id,
|
||||
network.gid,
|
||||
network.user_id,
|
||||
network.project_id
|
||||
)
|
||||
|
||||
|
||||
class DeleteNetwork(Command):
|
||||
"""
|
||||
Delete the specified network.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(DeleteNetwork, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteNetwork, self).get_parser(prog_name)
|
||||
parser.add_argument('network_id', metavar='<network-id>',
|
||||
help="Network ID")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
network = self.client.networks.delete(self.gid,
|
||||
parsed_args.network_id)
|
||||
|
|
@ -0,0 +1,249 @@
|
|||
# Copyright (c) 2014 ITOCHU Techno-Solutions Corporation.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import argparse
|
||||
|
||||
from cliff.command import Command
|
||||
from cliff.lister import Lister
|
||||
from cliff.show import ShowOne
|
||||
|
||||
from rackclient import client
|
||||
from rackclient import exceptions
|
||||
from rackclient import utils
|
||||
|
||||
|
||||
class PS(Lister):
|
||||
"""
|
||||
Print a list of all processes in the specified group.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(PS, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
processes = self.client.processes.list(self.gid)
|
||||
|
||||
def _make_command(process):
|
||||
p_args = process.args
|
||||
p_args.pop('gid')
|
||||
p_args.pop('pid')
|
||||
p_args.pop('ppid', None)
|
||||
p_args.pop('proxy_ip', None)
|
||||
p_args.pop('rackapi_ip', None)
|
||||
|
||||
cmd = process.name
|
||||
for k, v in sorted(p_args.items()):
|
||||
cmd += ' --' + k + ' ' + v
|
||||
|
||||
return cmd
|
||||
|
||||
return (
|
||||
('pid', 'ppid', 'command'),
|
||||
((p.pid, p.ppid, _make_command(p)) for p in processes)
|
||||
)
|
||||
|
||||
|
||||
def _make_print_data(pid, ppid, name, nova_instance_id, nova_flavor_id,
|
||||
glance_image_id, keypair_id, securitygroup_ids, networks,
|
||||
userdata, args, app_status, gid, user_id, project_id, status=None):
|
||||
columns = ['pid', 'ppid', 'name', 'nova_instance_id', 'nova_flavor_id',
|
||||
'glance_image_id', 'keypair_id', 'securitygroup_ids', 'networks',
|
||||
'userdata', 'args', 'app_status', 'gid', 'user_id', 'project_id']
|
||||
data = [pid, ppid, name, nova_instance_id, nova_flavor_id,
|
||||
glance_image_id, keypair_id, securitygroup_ids, networks,
|
||||
userdata, args, app_status, gid, user_id, project_id]
|
||||
|
||||
if status is not None:
|
||||
columns.append('status')
|
||||
data.append(status)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
class Show(ShowOne):
|
||||
"""
|
||||
Show details about the given process.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(Show, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Show, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument('pid', metavar='<pid>',
|
||||
help="process ID")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
process = self.client.processes.get(self.gid, parsed_args.pid)
|
||||
|
||||
sg_ids = process.securitygroup_ids
|
||||
if sg_ids:
|
||||
sg_ids = ','.join(sg_ids)
|
||||
|
||||
process_args = process.args
|
||||
if process_args:
|
||||
s = ''
|
||||
for k, v in sorted(process_args.items()):
|
||||
s += k + '=' + v + '\n'
|
||||
process_args = s.rstrip('\n')
|
||||
|
||||
return _make_print_data(
|
||||
process.pid,
|
||||
process.ppid,
|
||||
process.name,
|
||||
process.nova_instance_id,
|
||||
process.nova_flavor_id,
|
||||
process.glance_image_id,
|
||||
process.keypair_id,
|
||||
sg_ids,
|
||||
process.networks,
|
||||
process.userdata,
|
||||
process_args,
|
||||
process.app_status,
|
||||
process.gid,
|
||||
process.user_id,
|
||||
process.project_id,
|
||||
process.status
|
||||
)
|
||||
|
||||
|
||||
class Boot(ShowOne):
|
||||
"""
|
||||
Boot a process.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(Boot, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Boot, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument('--ppid', metavar='<ppid>',
|
||||
help="ID of a parent process")
|
||||
parser.add_argument('--name', metavar='<name>',
|
||||
help="Name of the new process")
|
||||
parser.add_argument('--flavor', metavar='<flavor-id>',
|
||||
help="ID of a flavor that is provided by Nova")
|
||||
parser.add_argument('--image', metavar='<image-id>',
|
||||
help="ID of a image that is provided by Glance")
|
||||
parser.add_argument('--keypair', metavar='<keypair-id>',
|
||||
help="Keypair ID")
|
||||
parser.add_argument('--securitygroup', metavar='<securitygroup-id>',
|
||||
dest='securitygroup_ids', action='append',
|
||||
default=[],
|
||||
help="Securitygroup ID (Can be repeated)")
|
||||
parser.add_argument('--userdata', metavar='</file/path>',
|
||||
help="Userdata file path")
|
||||
parser.add_argument('--args', metavar='<key1=value1,key2=value2,...>',
|
||||
type=utils.keyvalue_to_dict,
|
||||
help="Key-value pairs to be passed to metadata server")
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
userdata = None
|
||||
if parsed_args.userdata:
|
||||
try:
|
||||
userdata = open(parsed_args.userdata)
|
||||
except IOError:
|
||||
raise exceptions.CommandError(
|
||||
"Can't open '%s'" % parsed_args.userdata)
|
||||
|
||||
process = self.client.processes.create(
|
||||
gid=self.gid,
|
||||
ppid=parsed_args.ppid,
|
||||
name=parsed_args.name,
|
||||
nova_flavor_id=parsed_args.flavor,
|
||||
glance_image_id=parsed_args.image,
|
||||
keypair_id=parsed_args.keypair,
|
||||
securitygroup_ids=parsed_args.securitygroup_ids,
|
||||
userdata=userdata,
|
||||
args=parsed_args.args)
|
||||
|
||||
sg_ids = process.securitygroup_ids
|
||||
if sg_ids:
|
||||
sg_ids = ','.join(sg_ids)
|
||||
|
||||
process_args = process.args
|
||||
if process_args:
|
||||
s = ''
|
||||
for k, v in sorted(process_args.items()):
|
||||
s += k + '=' + v + '\n'
|
||||
process_args = s.rstrip('\n')
|
||||
|
||||
return _make_print_data(
|
||||
process.pid,
|
||||
process.ppid,
|
||||
process.name,
|
||||
process.nova_instance_id,
|
||||
process.nova_flavor_id,
|
||||
process.glance_image_id,
|
||||
process.keypair_id,
|
||||
sg_ids,
|
||||
process.networks,
|
||||
process.userdata,
|
||||
process_args,
|
||||
process.app_status,
|
||||
process.gid,
|
||||
process.user_id,
|
||||
process.project_id,
|
||||
)
|
||||
|
||||
|
||||
class Kill(Command):
|
||||
"""
|
||||
Delete the specified process.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(Kill, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Kill, self).get_parser(prog_name)
|
||||
parser.add_argument('pid', metavar='<pid>',
|
||||
help="process ID")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
process = self.client.processes.delete(self.gid, parsed_args.pid)
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
# Copyright (c) 2014 ITOCHU Techno-Solutions Corporation.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import argparse
|
||||
|
||||
from cliff.command import Command
|
||||
from cliff.lister import Lister
|
||||
from cliff.show import ShowOne
|
||||
|
||||
from rackclient import client
|
||||
|
||||
|
||||
def _make_print_data(pid, ppid, name, nova_instance_id, nova_flavor_id,
|
||||
glance_image_id, keypair_id, securitygroup_ids, networks,
|
||||
userdata, args, app_status, fs_endpoint, ipc_endpoint,
|
||||
shm_endpoint, gid, user_id, project_id, status=None):
|
||||
columns = ['pid', 'ppid', 'name', 'nova_instance_id', 'nova_flavor_id',
|
||||
'glance_image_id', 'keypair_id', 'securitygroup_ids', 'networks',
|
||||
'userdata', 'args', 'app_status', 'fs_endpoint', 'ipc_endpoint',
|
||||
'shm_endpoint', 'gid', 'user_id', 'project_id']
|
||||
data = [pid, ppid, name, nova_instance_id, nova_flavor_id,
|
||||
glance_image_id, keypair_id, securitygroup_ids, networks,
|
||||
userdata, args, app_status, fs_endpoint, ipc_endpoint,
|
||||
shm_endpoint, gid, user_id, project_id]
|
||||
|
||||
if status is not None:
|
||||
columns.append('status')
|
||||
data.append(status)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
class ShowProxy(ShowOne):
|
||||
"""
|
||||
Show details about the rack-proxy process.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(ShowProxy, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
proxy = self.client.proxy.get(self.gid)
|
||||
|
||||
sg_ids = proxy.securitygroup_ids
|
||||
if sg_ids:
|
||||
sg_ids = ','.join(sg_ids)
|
||||
|
||||
proxy_args = proxy.args
|
||||
if proxy_args:
|
||||
s = ''
|
||||
for k, v in sorted(proxy_args.items()):
|
||||
s += k + '=' + v + '\n'
|
||||
proxy_args = s.rstrip('\n')
|
||||
|
||||
return _make_print_data(
|
||||
proxy.pid,
|
||||
proxy.ppid,
|
||||
proxy.name,
|
||||
proxy.nova_instance_id,
|
||||
proxy.nova_flavor_id,
|
||||
proxy.glance_image_id,
|
||||
proxy.keypair_id,
|
||||
sg_ids,
|
||||
proxy.networks,
|
||||
proxy.userdata,
|
||||
proxy_args,
|
||||
proxy.app_status,
|
||||
proxy.fs_endpoint,
|
||||
proxy.ipc_endpoint,
|
||||
proxy.shm_endpoint,
|
||||
proxy.gid,
|
||||
proxy.user_id,
|
||||
proxy.project_id,
|
||||
proxy.status
|
||||
)
|
||||
|
||||
|
||||
class CreateProxy(ShowOne):
|
||||
"""
|
||||
Create a rack-proxy process.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(CreateProxy, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateProxy, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument('--name', metavar='<name>',
|
||||
help="Name of the rack-proxy process")
|
||||
parser.add_argument('--keypair', metavar='<keypair-id>',
|
||||
help="Keypair id of the new process uses")
|
||||
parser.add_argument('--securitygroup', metavar='<securitygroup-id>',
|
||||
dest='securitygroup', action='append',
|
||||
default=[],
|
||||
help="Securitygroup id the rack-proxy process belongs to (Can be repeated)")
|
||||
parser.add_argument('--flavor', metavar='<nova-flavor-id>',
|
||||
required=True,
|
||||
help="(Required) Flavor id of the rack-proxy process")
|
||||
parser.add_argument('--image', metavar='<glance-image-id>',
|
||||
required=True,
|
||||
help="(Required) Image id that registered on Glance of the rack-proxy process")
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
proxy = self.client.proxy.create(self.gid,
|
||||
name=parsed_args.name,
|
||||
nova_flavor_id=parsed_args.flavor,
|
||||
glance_image_id=parsed_args.image,
|
||||
keypair_id=parsed_args.keypair,
|
||||
securitygroup_ids=parsed_args.securitygroup)
|
||||
|
||||
sg_ids = proxy.securitygroup_ids
|
||||
if sg_ids:
|
||||
sg_ids = ','.join(sg_ids)
|
||||
|
||||
proxy_args = proxy.args
|
||||
if proxy_args:
|
||||
s = ''
|
||||
for k, v in sorted(proxy_args.items()):
|
||||
s += k + '=' + v + '\n'
|
||||
proxy_args = s.rstrip('\n')
|
||||
|
||||
return _make_print_data(
|
||||
proxy.pid,
|
||||
proxy.ppid,
|
||||
proxy.name,
|
||||
proxy.nova_instance_id,
|
||||
proxy.nova_flavor_id,
|
||||
proxy.glance_image_id,
|
||||
proxy.keypair_id,
|
||||
sg_ids,
|
||||
proxy.networks,
|
||||
proxy.userdata,
|
||||
proxy_args,
|
||||
proxy.app_status,
|
||||
proxy.fs_endpoint,
|
||||
proxy.ipc_endpoint,
|
||||
proxy.shm_endpoint,
|
||||
proxy.gid,
|
||||
proxy.user_id,
|
||||
proxy.project_id,
|
||||
proxy.status
|
||||
)
|
||||
|
||||
|
||||
class UpdateProxy(ShowOne):
|
||||
"""
|
||||
Update the rack-proxy process.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(UpdateProxy, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UpdateProxy, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument('--fs-endpoint', metavar='<fs-endpoint>',
|
||||
help="Endpoint of the shared memory service")
|
||||
parser.add_argument('--ipc-endpoint', metavar='<ipc-endpoint>',
|
||||
help="Endpoint of the IPC service")
|
||||
parser.add_argument('--shm-endpoint', metavar='<shm-endpoint>',
|
||||
help="Endpoint of the file system service")
|
||||
parser.add_argument('--app-status', metavar='<app-status>',
|
||||
help="Application layer status of the proxy")
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
proxy = self.client.proxy.update(self.gid,
|
||||
parsed_args.fs_endpoint,
|
||||
parsed_args.ipc_endpoint,
|
||||
parsed_args.shm_endpoint,
|
||||
parsed_args.app_status)
|
||||
|
||||
sg_ids = proxy.securitygroup_ids
|
||||
if sg_ids:
|
||||
sg_ids = ','.join(sg_ids)
|
||||
|
||||
proxy_args = proxy.args
|
||||
if proxy_args:
|
||||
s = ''
|
||||
for k, v in sorted(proxy_args.items()):
|
||||
s += k + '=' + v + '\n'
|
||||
proxy_args = s.rstrip('\n')
|
||||
|
||||
return _make_print_data(
|
||||
proxy.pid,
|
||||
proxy.ppid,
|
||||
proxy.name,
|
||||
proxy.nova_instance_id,
|
||||
proxy.nova_flavor_id,
|
||||
proxy.glance_image_id,
|
||||
proxy.keypair_id,
|
||||
sg_ids,
|
||||
proxy.networks,
|
||||
proxy.userdata,
|
||||
proxy_args,
|
||||
proxy.app_status,
|
||||
proxy.fs_endpoint,
|
||||
proxy.ipc_endpoint,
|
||||
proxy.shm_endpoint,
|
||||
proxy.gid,
|
||||
proxy.user_id,
|
||||
proxy.project_id
|
||||
)
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
# Copyright (c) 2014 ITOCHU Techno-Solutions Corporation.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import argparse
|
||||
|
||||
from cliff.command import Command
|
||||
from cliff.lister import Lister
|
||||
from cliff.show import ShowOne
|
||||
|
||||
from rackclient import client
|
||||
from rackclient import exceptions
|
||||
from rackclient import utils
|
||||
|
||||
|
||||
def _make_print_data(securitygroup_id, name, neutron_securitygroup_id,
|
||||
is_default, gid, user_id, project_id, status=None):
|
||||
columns = ['securitygroup_id', 'name', 'neutron_securitygroup_id',
|
||||
'is_default', 'gid', 'user_id', 'project_id']
|
||||
data = [securitygroup_id, name, neutron_securitygroup_id,
|
||||
is_default, gid, user_id, project_id]
|
||||
|
||||
if status is not None:
|
||||
columns.append('status')
|
||||
data.append(status)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
class ListSecuritygroups(Lister):
|
||||
"""
|
||||
Print a list of all security groups in the specified group.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(ListSecuritygroups, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
securitygroups = self.client.securitygroups.list(self.gid)
|
||||
return (
|
||||
('securitygroup_id', 'name', 'is_default', 'status'),
|
||||
((s.securitygroup_id, s.name, s.is_default, s.status) for s in securitygroups)
|
||||
)
|
||||
|
||||
|
||||
class ShowSecuritygroup(ShowOne):
|
||||
"""
|
||||
Show details about the given security group.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(ShowSecuritygroup, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowSecuritygroup, self).get_parser(prog_name)
|
||||
parser.add_argument('securitygroup_id', metavar='<securitygroup-id>',
|
||||
help="Securitygroup ID")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
securitygroup = self.client.securitygroups.get(self.gid,
|
||||
parsed_args.securitygroup_id)
|
||||
return _make_print_data(
|
||||
securitygroup.securitygroup_id,
|
||||
securitygroup.name,
|
||||
securitygroup.neutron_securitygroup_id,
|
||||
securitygroup.is_default,
|
||||
securitygroup.gid,
|
||||
securitygroup.user_id,
|
||||
securitygroup.project_id,
|
||||
securitygroup.status,
|
||||
)
|
||||
|
||||
|
||||
class CreateSecuritygroup(ShowOne):
|
||||
"""
|
||||
Create a new securitygroup.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(CreateSecuritygroup, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateSecuritygroup, self).get_parser(prog_name)
|
||||
parser.add_argument('--name', metavar='<name>',
|
||||
help="Name of the new securitygroup")
|
||||
parser.add_argument('--is-default', metavar='<true/false>',
|
||||
default=False,
|
||||
help="Defaults to the default securitygroup of the group")
|
||||
parser.add_argument('--rule',
|
||||
metavar=("<protocol=tcp|udp|icmp,port_range_max=integer,"
|
||||
"port_range_min=integer,remote_ip_prefix=cidr,"
|
||||
"remote_securitygroup_id=securitygroup_uuid>"),
|
||||
action='append',
|
||||
type=utils.keyvalue_to_dict,
|
||||
dest='rules',
|
||||
default=[],
|
||||
help=("Securitygroup rules. "
|
||||
"protocol: Protocol of packet, "
|
||||
"port_range_max: Starting port range, "
|
||||
"port_range_min: Ending port range, "
|
||||
"remote_ip_prefix: CIDR to match on, "
|
||||
"remote_securitygroup_id: Remote securitygroup id "
|
||||
"to apply rule. (Can be repeated)"))
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
securitygroup = self.client.securitygroups.create(self.gid,
|
||||
parsed_args.name,
|
||||
parsed_args.is_default,
|
||||
parsed_args.rules)
|
||||
|
||||
return _make_print_data(
|
||||
securitygroup.securitygroup_id,
|
||||
securitygroup.name,
|
||||
securitygroup.neutron_securitygroup_id,
|
||||
securitygroup.is_default,
|
||||
securitygroup.gid,
|
||||
securitygroup.user_id,
|
||||
securitygroup.project_id,
|
||||
)
|
||||
|
||||
|
||||
class UpdateSecuritygroup(ShowOne):
|
||||
"""
|
||||
Update the specified securitygroup.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(UpdateSecuritygroup, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UpdateSecuritygroup, self).get_parser(prog_name)
|
||||
parser.add_argument('securitygroup_id', metavar='<securitygroup-id>',
|
||||
help="Securitygroup ID")
|
||||
parser.add_argument('--is-default', metavar='<true/false>',
|
||||
required=True,
|
||||
help="Defaults to the default securitygroup of the group")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
securitygroup = self.client.securitygroups.update(self.gid,
|
||||
parsed_args.securitygroup_id,
|
||||
parsed_args.is_default)
|
||||
return _make_print_data(
|
||||
securitygroup.securitygroup_id,
|
||||
securitygroup.name,
|
||||
securitygroup.neutron_securitygroup_id,
|
||||
securitygroup.is_default,
|
||||
securitygroup.gid,
|
||||
securitygroup.user_id,
|
||||
securitygroup.project_id,
|
||||
)
|
||||
|
||||
|
||||
class DeleteSecuritygroup(Command):
|
||||
"""
|
||||
Delete the specified securitygroup.
|
||||
"""
|
||||
def __init__(self, app, app_args):
|
||||
super(DeleteSecuritygroup, self).__init__(app, app_args)
|
||||
|
||||
# When the help command is called,
|
||||
# the type of 'app_args' is list.
|
||||
if isinstance(app_args, argparse.Namespace):
|
||||
self.client = client.Client(app_args.rack_api_version,
|
||||
rack_url=app_args.rack_url,
|
||||
http_log_debug=app_args.debug)
|
||||
self.gid = app_args.gid
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteSecuritygroup, self).get_parser(prog_name)
|
||||
parser.add_argument('securitygroup_id', metavar='<securitygroup-id>',
|
||||
help="Securitygroup ID")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
securitygroup = self.client.securitygroups.delete(self.gid,
|
||||
parsed_args.securitygroup_id)
|
||||
|
|
@ -1,805 +0,0 @@
|
|||
# Copyright (c) 2014 ITOCHU Techno-Solutions Corporation.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from ConfigParser import ConfigParser
|
||||
from ConfigParser import NoOptionError
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import prettytable
|
||||
|
||||
from oslo.utils import strutils
|
||||
from rackclient import exceptions
|
||||
from rackclient.openstack.common import cliutils
|
||||
from rackclient.openstack.common.gettextutils import _
|
||||
from rackclient.v1.syscall.default import signal
|
||||
from rackclient.v1.syscall.default import file as rackfile
|
||||
|
||||
|
||||
def _keyvalue_to_dict(text):
|
||||
try:
|
||||
d = {}
|
||||
pairs = text.split(',')
|
||||
for pair in pairs:
|
||||
(k, v) = pair.split('=', 1)
|
||||
d.update({k: v})
|
||||
return d
|
||||
except ValueError:
|
||||
msg = "%r is not in the format of key=value" % text
|
||||
raise argparse.ArgumentTypeError(msg)
|
||||
|
||||
|
||||
def do_group_list(cs, args):
|
||||
"""
|
||||
Print a list of all groups.
|
||||
"""
|
||||
groups = cs.groups.list()
|
||||
fields = ['gid', 'name', 'description', 'status']
|
||||
print_list(groups, fields, sortby='gid')
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'gid',
|
||||
metavar='<gid>',
|
||||
help=_("Group id"))
|
||||
def do_group_show(cs, args):
|
||||
"""
|
||||
Show details about the given group.
|
||||
"""
|
||||
group = cs.groups.get(args.gid)
|
||||
keypairs = cs.keypairs.list(args.gid)
|
||||
securitygroups = cs.securitygroups.list(args.gid)
|
||||
networks = cs.networks.list(args.gid)
|
||||
processes = cs.processes.list(args.gid)
|
||||
try:
|
||||
proxy = cs.proxy.get(args.gid)
|
||||
except Exception:
|
||||
proxy = None
|
||||
d = group._info
|
||||
d.update({
|
||||
"keypairs": ','.join([x.keypair_id for x in keypairs]),
|
||||
"securitygroups": ','.join([x.securitygroup_id for x in securitygroups]),
|
||||
"networks": ','.join([x.network_id for x in networks]),
|
||||
"processes (pid)": ','.join([x.pid for x in processes]),
|
||||
"proxy (pid)": proxy.pid if proxy else ''
|
||||
})
|
||||
print_dict(d)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'name',
|
||||
metavar='<name>',
|
||||
help=_("Name of the new group"))
|
||||
@cliutils.arg(
|
||||
'--description',
|
||||
metavar='<description>',
|
||||
help=_("Details of the new group"))
|
||||
def do_group_create(cs, args):
|
||||
"""
|
||||
Create a new group.
|
||||
"""
|
||||
group = cs.groups.create(args.name, args.description)
|
||||
d = group._info
|
||||
print_dict(d)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'gid',
|
||||
metavar='<gid>',
|
||||
help=_("Group id"))
|
||||
@cliutils.arg(
|
||||
'--name',
|
||||
metavar='<name>',
|
||||
help=_("Name of the group"))
|
||||
@cliutils.arg(
|
||||
'--description',
|
||||
metavar='<description>',
|
||||
help=_("Details of the group"))
|
||||
def do_group_update(cs, args):
|
||||
"""
|
||||
Update the specified group.
|
||||
"""
|
||||
group = cs.groups.update(args.gid, args.name, args.description)
|
||||
d = group._info
|
||||
print_dict(d)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'gid',
|
||||
metavar='<gid>',
|
||||
help=_("Group id"))
|
||||
def do_group_delete(cs, args):
|
||||
"""
|
||||
Delete the specified group.
|
||||
"""
|
||||
cs.groups.delete(args.gid)
|
||||
|
||||
|
||||
def do_keypair_list(cs, args):
|
||||
"""
|
||||
Print a list of all keypairs in the specified group.
|
||||
"""
|
||||
keypairs = cs.keypairs.list(args.gid)
|
||||
fields = ['keypair_id', 'name', 'is_default', 'status']
|
||||
print_list(keypairs, fields, sortby='keypair_id')
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'keypair_id',
|
||||
metavar='<keypair_id>',
|
||||
help=_("Keypair ID"))
|
||||
def do_keypair_show(cs, args):
|
||||
"""
|
||||
Show details about the given keypair.
|
||||
"""
|
||||
keypair = cs.keypairs.get(args.gid, args.keypair_id)
|
||||
d = keypair._info
|
||||
print_dict(d)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'--name',
|
||||
metavar='<name>',
|
||||
help=_("Name of the new keypair"))
|
||||
@cliutils.arg(
|
||||
'--is_default',
|
||||
metavar='<is_default>',
|
||||
help=_("Defaults to the default keypair of the group"),
|
||||
type=lambda v: strutils.bool_from_string(v, True),
|
||||
default=False)
|
||||
def do_keypair_create(cs, args):
|
||||
"""
|
||||
Create a new keypair.
|
||||
"""
|
||||
keypair = cs.keypairs.create(args.gid, args.name, args.is_default)
|
||||
d = keypair._info
|
||||
print_dict(d)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'keypair_id',
|
||||
metavar='<keypair_id>',
|
||||
help=_("Keypair id"))
|
||||
@cliutils.arg(
|
||||
'--is_default',
|
||||
metavar='<is_default>',
|
||||
help=_("Defaults to the default keypair of the group"),
|
||||
type=lambda v: strutils.bool_from_string(v, True),
|
||||
default=True)
|
||||
def do_keypair_update(cs, args):
|
||||
"""
|
||||
Update the specified keypair.
|
||||
"""
|
||||
keypair = cs.keypairs.update(args.gid, args.keypair_id, args.is_default)
|
||||
d = keypair._info
|
||||
print_dict(d)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'keypair_id',
|
||||
metavar='<keypair_id>',
|
||||
help=_("Keypair id"))
|
||||
def do_keypair_delete(cs, args):
|
||||
"""
|
||||
Delete the specified keypair.
|
||||
"""
|
||||
cs.keypairs.delete(args.gid, args.keypair_id)
|
||||
|
||||
|
||||
def do_securitygroup_list(cs, args):
|
||||
"""
|
||||
Print a list of all security groups in the specified group.
|
||||
"""
|
||||
securitygroups = cs.securitygroups.list(args.gid)
|
||||
fields = [
|
||||
'securitygroup_id', 'name', 'is_default', 'status'
|
||||
]
|
||||
print_list(securitygroups, fields, sortby='securitygroup_id')
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'securitygroup_id',
|
||||
metavar='<securitygroup_id>',
|
||||
help=_("Securitygroup id"))
|
||||
def do_securitygroup_show(cs, args):
|
||||
"""
|
||||
Show details about the given security group.
|
||||
"""
|
||||
securitygroup = cs.securitygroups.get(args.gid, args.securitygroup_id)
|
||||
d = securitygroup._info
|
||||
print_dict(d)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'--name',
|
||||
metavar='<name>',
|
||||
help=_("Name of the new securitygroup"))
|
||||
@cliutils.arg(
|
||||
'--is_default',
|
||||
metavar='<is_default>',
|
||||
help=_("Defaults to the default securitygroup of the group"),
|
||||
type=lambda v: strutils.bool_from_string(v, True),
|
||||
default=False)
|
||||
@cliutils.arg(
|
||||
'--rule',
|
||||
metavar="<protocol=tcp|udp|icmp,port_range_max=integer,"
|
||||
"port_range_min=integer,remote_ip_prefix=cidr,"
|
||||
"remote_securitygroup_id=securitygroup_uuid>",
|
||||
action='append',
|
||||
type=_keyvalue_to_dict,
|
||||
dest='rules',
|
||||
default=[],
|
||||
help=_("Securitygroup rules. "
|
||||
"protocol: Protocol of packet, "
|
||||
"port_range_max: Starting port range, "
|
||||
"port_range_min: Ending port range, "
|
||||
"remote_ip_prefix: CIDR to match on, "
|
||||
"remote_securitygroup_id: Remote securitygroup id to apply rule. "
|
||||
"(Can be repeated)"))
|
||||
def do_securitygroup_create(cs, args):
|
||||
"""
|
||||
Create a new security group.
|
||||
"""
|
||||
securitygroup = cs.securitygroups.create(args.gid,
|
||||
args.name,
|
||||
args.is_default,
|
||||
args.rules)
|
||||
d = securitygroup._info
|
||||
print_dict(d)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'securitygroup_id',
|
||||
metavar='<securitygroup_id>',
|
||||
help=_("Securitygroup id"))
|
||||
@cliutils.arg(
|
||||
'--is_default',
|
||||
metavar='<is_default>',
|
||||
help=_("Defaults to the default securitygroup of the group"),
|
||||
type=lambda v: strutils.bool_from_string(v, True),
|
||||
default=True)
|
||||
def do_securitygroup_update(cs, args):
|
||||
"""
|
||||
Update the specified security group.
|
||||
"""
|
||||
securitygroup = cs.securitygroups.update(args.gid,
|
||||
args.securitygroup_id,
|
||||
args.is_default)
|
||||
d = securitygroup._info
|
||||
print_dict(d)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'securitygroup_id',
|
||||
metavar='<securitygroup_id>',
|
||||
help=_("Securitygroup id"))
|
||||
def do_securitygroup_delete(cs, args):
|
||||
"""
|
||||
Delete the specified security group.
|
||||
"""
|
||||
cs.securitygroups.delete(args.gid, args.securitygroup_id)
|
||||
|
||||
|
||||
def do_network_list(cs, args):
|
||||
"""
|
||||
Print a list of all networks in the specified group.
|
||||
"""
|
||||
networks = cs.networks.list(args.gid)
|
||||
fields = [
|
||||
'network_id', 'name', 'is_admin', 'status'
|
||||
]
|
||||
print_list(networks, fields, sortby='network_id')
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'network_id',
|
||||
metavar='<network_id>',
|
||||
help=_("network id"))
|
||||
def do_network_show(cs, args):
|
||||
"""
|
||||
Show details about the given network.
|
||||
"""
|
||||
network = cs.networks.get(args.gid, args.network_id)
|
||||
d = network._info
|
||||
print_dict(d)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'cidr',
|
||||
metavar='<cidr>',
|
||||
help=_("CIDR of the new network"))
|
||||
@cliutils.arg(
|
||||
'--name',
|
||||
metavar='<name>',
|
||||
help=_("Name of the new network"))
|
||||
@cliutils.arg(
|
||||
'--is_admin',
|
||||
metavar='<is_admin>',
|
||||
help=_(""),
|
||||
type=lambda v: strutils.bool_from_string(v, True),
|
||||
default=False)
|
||||
@cliutils.arg(
|
||||
'--gateway_ip',
|
||||
metavar='<gateway_ip>',
|
||||
help=_("Gateway ip address of the new network"))
|
||||
@cliutils.arg(
|
||||
'--dns_nameserver',
|
||||
metavar='<dns_nameserver>',
|
||||
dest='dns_nameservers',
|
||||
action='append',
|
||||
help=_("DNS server for the new network (Can be repeated)"))
|
||||
@cliutils.arg(
|
||||
'--ext_router_id',
|
||||
metavar='<ext_router_id>',
|
||||
help=_("Router id the new network connects to"))
|
||||
def do_network_create(cs, args):
|
||||
"""
|
||||
Create a network.
|
||||
"""
|
||||
network = cs.networks.create(args.gid,
|
||||
args.cidr,
|
||||
args.name,
|
||||
args.is_admin,
|
||||
args.gateway_ip,
|
||||
args.dns_nameservers,
|
||||
args.ext_router_id)
|
||||
d = network._info
|
||||
print_dict(d)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'network_id',
|
||||
metavar='<network_id>',
|
||||
help=_("network id"))
|
||||
def do_network_delete(cs, args):
|
||||
"""
|
||||
Delete the specified network.
|
||||
"""
|
||||
cs.networks.delete(args.gid, args.network_id)
|
||||
|
||||
|
||||
def do_process_list(cs, args):
|
||||
"""
|
||||
Print a list of all processes in the specified group.
|
||||
"""
|
||||
processes = cs.processes.list(args.gid)
|
||||
fields = [
|
||||
'pid', 'ppid', 'name', 'status'
|
||||
]
|
||||
print_list(processes, fields, sortby='pid')
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'pid',
|
||||
metavar='<pid>',
|
||||
help=_("process ID"))
|
||||
def do_process_show(cs, args):
|
||||
"""
|
||||
Show details about the given process.
|
||||
"""
|
||||
process = cs.processes.get(args.gid, args.pid)
|
||||
d = process._info
|
||||
print_process(d)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'--ppid',
|
||||
metavar='<ppid>',
|
||||
help=_("Parent process id of the new process"))
|
||||
@cliutils.arg(
|
||||
'--name',
|
||||
metavar='<name>',
|
||||
help=_("Name of the new process"))
|
||||
@cliutils.arg(
|
||||
'--nova_flavor_id',
|
||||
metavar='<nova_flavor_id>',
|
||||
help=_("Flavor id of the new process"))
|
||||
@cliutils.arg(
|
||||
'--glance_image_id',
|
||||
metavar='<glance_image_id>',
|
||||
help=_("Image id that registered on Glance of the new process"))
|
||||
@cliutils.arg(
|
||||
'--keypair_id',
|
||||
metavar='<keypair_id>',
|
||||
help=_("Keypair id of the new process uses"))
|
||||
@cliutils.arg(
|
||||
'--securitygroup_id',
|
||||
metavar='<securitygroup_id>',
|
||||
dest='securitygroup_ids',
|
||||
action='append',
|
||||
default=[],
|
||||
help=_("Securitygroup id the new process belongs to (Can be repeated)"))
|
||||
@cliutils.arg(
|
||||
'--userdata',
|
||||
metavar='<userdata>',
|
||||
help=_("Userdata file to pass"))
|
||||
@cliutils.arg(
|
||||
'--args',
|
||||
metavar='<key1=value1,key2=value2 or a file including key=value lines>',
|
||||
help=_("Key-value pairs to be passed to metadata server"))
|
||||
def do_process_create(cs, args):
|
||||
"""
|
||||
Create a new process.
|
||||
"""
|
||||
if args.userdata:
|
||||
try:
|
||||
userdata = open(args.userdata)
|
||||
except IOError as e:
|
||||
raise exceptions.CommandError(
|
||||
_("Can't open '%s'") % args.userdata)
|
||||
else:
|
||||
userdata = None
|
||||
|
||||
if args.args:
|
||||
if os.path.exists(args.args):
|
||||
try:
|
||||
f = open(args.args)
|
||||
options = {}
|
||||
for line in f:
|
||||
k, v = line.split('=', 1)
|
||||
options.update({k.strip(): v.strip()})
|
||||
except IOError as e:
|
||||
raise exceptions.CommandError(
|
||||
_("Can't open '%s'") % args.args)
|
||||
except ValueError:
|
||||
raise exceptions.CommandError(
|
||||
_("%s is not the format of key=value lines") % args.args)
|
||||
else:
|
||||
try:
|
||||
options = _keyvalue_to_dict(args.args)
|
||||
except argparse.ArgumentTypeError as e:
|
||||
raise exceptions.CommandError(e)
|
||||
else:
|
||||
options = None
|
||||
|
||||
process = cs.processes.create(args.gid,
|
||||
ppid=args.ppid,
|
||||
name=args.name,
|
||||
nova_flavor_id=args.nova_flavor_id,
|
||||
glance_image_id=args.glance_image_id,
|
||||
keypair_id=args.keypair_id,
|
||||
securitygroup_ids=args.securitygroup_ids,
|
||||
userdata=userdata,
|
||||
args=options)
|
||||
d = process._info
|
||||
print_process(d)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'pid',
|
||||
metavar='<pid>',
|
||||
help=_("Process id"))
|
||||
@cliutils.arg(
|
||||
'--app_status',
|
||||
metavar='<app_status>',
|
||||
help=_("Application layer status of the process"))
|
||||
def do_process_update(cs, args):
|
||||
"""
|
||||
Update the specified process.
|
||||
"""
|
||||
process = cs.processes.update(args.gid, args.pid, args.app_status)
|
||||
d = process._info
|
||||
print_process(d)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'pid',
|
||||
metavar='<pid>',
|
||||
help=_("Process id"))
|
||||
def do_process_delete(cs, args):
|
||||
"""
|
||||
Delete the specified process.
|
||||
"""
|
||||
cs.processes.delete(args.gid, args.pid)
|
||||
|
||||
|
||||
def do_proxy_show(cs, args):
|
||||
"""
|
||||
Show details about the given rack-proxy process.
|
||||
"""
|
||||
proxy = cs.proxy.get(args.gid)
|
||||
d = proxy._info
|
||||
print_process(d)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'--name',
|
||||
metavar='<name>',
|
||||
help=_("Name of the new process"))
|
||||
@cliutils.arg(
|
||||
'--nova_flavor_id',
|
||||
metavar='<nova_flavor_id>',
|
||||
help=_("Flavor id of the new process"))
|
||||
@cliutils.arg(
|
||||
'--glance_image_id',
|
||||
metavar='<glance_image_id>',
|
||||
help=_("Image id that registered on Glance of the new process"))
|
||||
@cliutils.arg(
|
||||
'--keypair_id',
|
||||
metavar='<keypair_id>',
|
||||
help=_("Keypair id of the new process uses"))
|
||||
@cliutils.arg(
|
||||
'--securitygroup_id',
|
||||
metavar='<securitygroup_id>',
|
||||
dest='securitygroup_ids',
|
||||
action='append',
|
||||
default=[],
|
||||
help=_("Securitygroup id the new process belongs to (Can be repeated)"))
|
||||
@cliutils.arg(
|
||||
'--userdata',
|
||||
metavar='<userdata>',
|
||||
help=_("Userdata file to pass"))
|
||||
@cliutils.arg(
|
||||
'--args',
|
||||
metavar='<key1=value1,key2=value2 or a file including key=value lines>',
|
||||
help=_("Key-value pairs to be passed to metadata server"))
|
||||
def do_proxy_create(cs, args):
|
||||
"""
|
||||
Create a new rack-proxy process.
|
||||
"""
|
||||
if args.userdata:
|
||||
try:
|
||||
userdata = open(args.userdata)
|
||||
except IOError as e:
|
||||
raise exceptions.CommandError(
|
||||
_("Can't open '%s'") % args.userdata)
|
||||
else:
|
||||
userdata = None
|
||||
|
||||
if args.args:
|
||||
if os.path.exists(args.args):
|
||||
try:
|
||||
f = open(args.args)
|
||||
options = {}
|
||||
for line in f:
|
||||
k, v = line.split('=', 1)
|
||||
options.update({k.strip(): v.strip()})
|
||||
except IOError as e:
|
||||
raise exceptions.CommandError(
|
||||
_("Can't open '%s'") % args.args)
|
||||
except ValueError:
|
||||
raise exceptions.CommandError(
|
||||
_("%s is not the format of key=value lines") % args.args)
|
||||
else:
|
||||
try:
|
||||
options = _keyvalue_to_dict(args.args)
|
||||
except argparse.ArgumentTypeError as e:
|
||||
raise exceptions.CommandError(e)
|
||||
else:
|
||||
options = None
|
||||
|
||||
proxy = cs.proxy.create(args.gid,
|
||||
name=args.name,
|
||||
nova_flavor_id=args.nova_flavor_id,
|
||||
glance_image_id=args.glance_image_id,
|
||||
keypair_id=args.keypair_id,
|
||||
securitygroup_ids=args.securitygroup_ids,
|
||||
userdata=userdata,
|
||||
args=options)
|
||||
d = proxy._info
|
||||
print_process(d)
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'--shm_endpoint',
|
||||
metavar='<shm_endpoint>',
|
||||
help=_("Endpoint of the shared memory service"))
|
||||
@cliutils.arg(
|
||||
'--ipc_endpoint',
|
||||
metavar='<ipc_endpoint>',
|
||||
help=_("Endpoint of the IPC service"))
|
||||
@cliutils.arg(
|
||||
'--fs_endpoint',
|
||||
metavar='<fs_endpoint>',
|
||||
help=_("Endpoint of the file system service"))
|
||||
@cliutils.arg(
|
||||
'--app_status',
|
||||
metavar='<app_status>',
|
||||
help=_("Application layer status of the proxy"))
|
||||
def do_proxy_update(cs, args):
|
||||
"""
|
||||
Update the specified rack-proxy process.
|
||||
"""
|
||||
proxy = cs.proxy.update(args.gid,
|
||||
args.shm_endpoint,
|
||||
args.ipc_endpoint,
|
||||
args.fs_endpoint,
|
||||
args.app_status)
|
||||
d = proxy._info
|
||||
print_process(d)
|
||||
|
||||
|
||||
def print_process(d):
|
||||
securitygroup_ids = d.get('securitygroup_ids')
|
||||
if securitygroup_ids:
|
||||
d['securitygroup_ids'] = ','.join(securitygroup_ids)
|
||||
|
||||
network_ids = d.get('network_ids')
|
||||
if network_ids:
|
||||
d['network_ids'] = ','.join(network_ids)
|
||||
|
||||
args = d.get('args')
|
||||
if args:
|
||||
s = ''
|
||||
for k, v in args.items():
|
||||
s += k + '=' + v + '\n'
|
||||
d['args'] = s.rstrip('\n')
|
||||
|
||||
print_dict(d)
|
||||
|
||||
|
||||
def print_list(objects, fields, sortby=None):
|
||||
pt = prettytable.PrettyTable(fields)
|
||||
pt.align = 'l'
|
||||
for o in objects:
|
||||
row = []
|
||||
for f in fields:
|
||||
row.append(getattr(o, f, ''))
|
||||
pt.add_row(row)
|
||||
print(pt.get_string(sortby=sortby))
|
||||
|
||||
|
||||
def print_dict(d):
|
||||
pt = prettytable.PrettyTable(['Property', 'Value'])
|
||||
pt.align = 'l'
|
||||
for k, v in sorted(d.items()):
|
||||
pt.add_row([k, v])
|
||||
print(pt.get_string())
|
||||
|
||||
|
||||
@cliutils.arg(
|
||||
'config',
|
||||
metavar='<config-file>',
|
||||
help=_("Configuration file included parameters of the new group"))
|
||||
def do_group_init(cs, args):
|
||||
"""
|
||||
Create a group, a keypair, a security group, a network and
|
||||
a rack-proxy based on the specified configuration file.
|
||||
"""
|
||||
config = ConfigParser()
|
||||
config.read(args.config)
|
||||
|
||||
# Create a group
|
||||
try:
|
||||
name = config.get('group', 'name')
|
||||
except NoOptionError:
|
||||
raise exceptions.CommandError(_("Group name is required."))
|
||||
try:
|
||||
description = config.get('group', 'description')
|
||||
except NoOptionError:
|
||||
description = None
|
||||
|
||||
group = cs.groups.create(name, description)
|
||||
d = group._info
|
||||
print_dict(d)
|
||||
|
||||
gid = group.gid
|
||||
|
||||
# Create a keypair
|
||||
try:
|
||||
name = config.get('keypair', 'name')
|
||||
except NoOptionError:
|
||||
name = None
|
||||
try:
|
||||
is_default = config.get('keypair', 'is_default')
|
||||
except NoOptionError:
|
||||
is_default = False
|
||||
|
||||
keypair = cs.keypairs.create(gid, name, is_default)
|
||||
d = keypair._info
|
||||
print_dict(d)
|
||||
|
||||
# Create a securitygroup
|
||||
try:
|
||||
name = config.get('securitygroup', 'name')
|
||||
except NoOptionError:
|
||||
name = None
|
||||
try:
|
||||
is_default = config.get('securitygroup', 'is_default')
|
||||
except NoOptionError:
|
||||
is_default = False
|
||||
try:
|
||||
rules = config.get('securitygroup', 'rules').split()
|
||||
for i in range(len(rules)):
|
||||
rules[i] = _keyvalue_to_dict(rules[i])
|
||||
except NoOptionError:
|
||||
rules = []
|
||||
except argparse.ArgumentTypeError as e:
|
||||
raise exceptions.CommandError(
|
||||
_("Could not create a securitygroup: "
|
||||
"securitygroup rules are not valid formart: %s") % e.message)
|
||||
|
||||
securitygroup = cs.securitygroups.create(gid, name, is_default, rules)
|
||||
d = securitygroup._info
|
||||
print_dict(d)
|
||||
|
||||
# Create a network
|
||||
try:
|
||||
cidr = config.get('network', 'cidr')
|
||||
except NoOptionError:
|
||||
raise exceptions.CommandError(_("Network cidr is required."))
|
||||
try:
|
||||
name = config.get('network', 'name')
|
||||
except NoOptionError:
|
||||
name = None
|
||||
try:
|
||||
is_admin = config.get('network', 'is_admin')
|
||||
except NoOptionError:
|
||||
is_admin = False
|
||||
try:
|
||||
gateway_ip = config.get('network', 'gateway_ip')
|
||||
except NoOptionError:
|
||||
gateway_ip = None
|
||||
try:
|
||||
dns_nameservers = config.get('network', 'dns_nameservers').split()
|
||||
except NoOptionError:
|
||||
dns_nameservers = []
|
||||
try:
|
||||
ext_router_id = config.get('network', 'ext_router_id')
|
||||
except NoOptionError:
|
||||
ext_router_id = None
|
||||
|
||||
network = cs.networks.create(gid, cidr, name, is_admin,
|
||||
gateway_ip, dns_nameservers, ext_router_id)
|
||||
d = network._info
|
||||
print_dict(d)
|
||||
|
||||
# Create a proxy
|
||||
try:
|
||||
name = config.get('proxy', 'name')
|
||||
except NoOptionError:
|
||||
name = None
|
||||
try:
|
||||
nova_flavor_id = config.get('proxy', 'nova_flavor_id')
|
||||
except NoOptionError:
|
||||
raise exceptions.CommandError(_("Flavor id is required."))
|
||||
try:
|
||||
glance_image_id = config.get('proxy', 'glance_image_id')
|
||||
except NoOptionError:
|
||||
raise exceptions.CommandError(_("Image id is required."))
|
||||
keypair_id = keypair.keypair_id
|
||||
securitygroup_ids = [securitygroup.securitygroup_id]
|
||||
try:
|
||||
userdata = config.get('proxy', 'userdata')
|
||||
userdata = open(userdata)
|
||||
except NoOptionError:
|
||||
userdata = None
|
||||
except IOError:
|
||||
raise exceptions.CommandError(
|
||||
_("Can't open %s.") % userdata)
|
||||
try:
|
||||
proxy_args = config.get('proxy', 'args')
|
||||
proxy_args = _keyvalue_to_dict(proxy_args)
|
||||
except NoOptionError:
|
||||
proxy_args = None
|
||||
except argparse.ArgumentTypeError as e:
|
||||
raise exceptions.CommandError(e)
|
||||
|
||||
proxy = cs.proxy.create(gid, name=name,
|
||||
nova_flavor_id=nova_flavor_id,
|
||||
glance_image_id=glance_image_id,
|
||||
keypair_id=keypair_id,
|
||||
securitygroup_ids=securitygroup_ids,
|
||||
userdata=userdata,
|
||||
args=proxy_args)
|
||||
d = proxy._info
|
||||
print_process(d)
|
||||
|
||||
result_dict = {
|
||||
"gid": gid,
|
||||
"keypair_id": keypair_id,
|
||||
"securitygroup_id": securitygroup.securitygroup_id,
|
||||
"network_id": network.network_id,
|
||||
"proxy pid": proxy.pid
|
||||
}
|
||||
print_dict(result_dict)
|
|
@ -1,3 +1,4 @@
|
|||
pbr>=0.10.8
|
||||
requests>=1.1.0
|
||||
redis>=2.10.3
|
||||
Babel>=1.3
|
||||
|
@ -9,3 +10,4 @@ PrettyTable>=0.7,<0.8
|
|||
websocket-client>=0.16.0
|
||||
python-keystoneclient>=0.11.2
|
||||
pika>=0.9.14
|
||||
cliff>=1.9.0
|
||||
|
|
32
setup.cfg
32
setup.cfg
|
@ -25,3 +25,35 @@ packages =
|
|||
[entry_points]
|
||||
console_scripts =
|
||||
rack = rackclient.shell:main
|
||||
rack.command =
|
||||
group-list = rackclient.v1.command.groups:ListGroups
|
||||
group-show = rackclient.v1.command.groups:ShowGroup
|
||||
group-create = rackclient.v1.command.groups:CreateGroup
|
||||
group-update = rackclient.v1.command.groups:UpdateGroup
|
||||
group-delete = rackclient.v1.command.groups:DeleteGroup
|
||||
group-init = rackclient.v1.command.groups:InitGroup
|
||||
keypair-list = rackclient.v1.command.keypairs:ListKeypairs
|
||||
keypair-show = rackclient.v1.command.keypairs:ShowKeypair
|
||||
keypair-create = rackclient.v1.command.keypairs:CreateKeypair
|
||||
keypair-update = rackclient.v1.command.keypairs:UpdateKeypair
|
||||
keypair-delete = rackclient.v1.command.keypairs:DeleteKeypair
|
||||
securitygroup-list = rackclient.v1.command.securitygroups:ListSecuritygroups
|
||||
securitygroup-show = rackclient.v1.command.securitygroups:ShowSecuritygroup
|
||||
securitygroup-create = rackclient.v1.command.securitygroups:CreateSecuritygroup
|
||||
securitygroup-update = rackclient.v1.command.securitygroups:UpdateSecuritygroup
|
||||
securitygroup-delete = rackclient.v1.command.securitygroups:DeleteSecuritygroup
|
||||
network-list = rackclient.v1.command.networks:ListNetworks
|
||||
network-show = rackclient.v1.command.networks:ShowNetwork
|
||||
network-create = rackclient.v1.command.networks:CreateNetwork
|
||||
network-delete = rackclient.v1.command.networks:DeleteNetwork
|
||||
proxy-show = rackclient.v1.command.proxy:ShowProxy
|
||||
proxy-create = rackclient.v1.command.proxy:CreateProxy
|
||||
proxy-update = rackclient.v1.command.proxy:UpdateProxy
|
||||
ps = rackclient.v1.command.processes:PS
|
||||
show = rackclient.v1.command.processes:Show
|
||||
boot = rackclient.v1.command.processes:Boot
|
||||
kill = rackclient.v1.command.processes:Kill
|
||||
|
||||
# applications
|
||||
montecarlo = rackclient.v1.command.montecarlo:Montecarlo
|
||||
|
||||
|
|
Loading…
Reference in New Issue