-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 73a5325
Showing
28 changed files
with
1,014 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# colosseumcli-18.05.0 |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import sys | ||
from colosseum_cli import colosseum_cli_constants as con | ||
from cliff.app import App | ||
from cliff.commandmanager import CommandManager | ||
|
||
|
||
class ColCliApp(App): | ||
def __init__(self): | ||
super(ColCliApp, self).__init__( | ||
description='colosseum cli app', | ||
version=con.CLI_APP_VERION, | ||
command_manager=CommandManager('cliff.colosseum'), | ||
deferred_help=True, | ||
) | ||
|
||
def initialize_app(self, argv): | ||
self.LOG.debug('initialize_app') | ||
|
||
def prepare_to_run_command(self, cmd): | ||
self.LOG.debug('prepare_to_run_command %s', cmd.__class__.__name__) | ||
|
||
def clean_up(self, cmd, result, err): | ||
self.LOG.debug('clean_up %s', cmd.__class__.__name__) | ||
if err: | ||
self.LOG.debug('got an error: %s', err) | ||
|
||
|
||
def main(argv=sys.argv[1:]): | ||
myapp = ColCliApp() | ||
return myapp.run(argv) | ||
|
||
|
||
if __name__ == '__main__': | ||
sys.exit(main(sys.argv[1:])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
""" | ||
Competitor CLI Constants | ||
""" | ||
CLI_APP_VERION = '18.05.0' | ||
CLI_MSG_VERSION = '2.0' | ||
|
||
SOCKET_PATH = '/socket/clisocket' | ||
TEST_SOCKET_PATH = '/tmp/socket/' | ||
TEST_SOCKET = TEST_SOCKET_PATH + 'clisocket' | ||
|
||
CLI_TEST_MODE_ENV = 'COLOSSEMCLI_TEST_MODE' | ||
|
||
#Sending Json keys | ||
CLI_CMD_KEY = "command" | ||
CLI_VER_KEY = "version" | ||
CLI_SNAPSHOT_FILE_KEY = "filename" | ||
CLI_SNAPSHOT_PATH_KEY = "path" | ||
CLI_SCEN_ID_KEY = "scenario_id" | ||
CLI_SCEN_RADIO_MAP_KEY = "srn_radio_mapping" | ||
CLI_SCEN_CYCLE_KEY = "scenario_cycle" | ||
|
||
#Sending Json values | ||
CLI_CMD_CTNR_SNAPSHOT = "snapshot" | ||
CLI_CMD_SCEN_START = "rf_scenario_start" | ||
CLI_CMD_SCEN_STOP = "rf_scenario_stop" | ||
CLI_CMD_SCEN_INFO = "rf_scenario_info" | ||
CLI_CMD_SCEN_LIST = "rf_scenario_list" | ||
CLI_CMD_TGEN_START = "tgen_start" | ||
CLI_CMD_TGEN_STOP = "tgen_stop" | ||
CLI_CMD_TGEN_INFO = "tgen_info" | ||
CLI_CMD_TGEN_LIST = "tgen_list" | ||
CLI_SNAPSHOT_PATH = "" | ||
|
||
CLI_CMD_GPS_START = "gps_start" | ||
CLI_CMD_GPS_STOP = "gps_stop" | ||
CLI_CMD_GPS_SCEN_LIST = "gps_scenario_list" | ||
CLI_CMD_GPS_INFO = "gps_info" | ||
CLI_CMD_GPS_UNIX_SOCKET = "/socket/gpssocket" | ||
CLI_CMD_GPS_RFID_KEY = "gps_rfid" | ||
CLI_CMD_GPS_NODEID_KEY = "gps_nodeid" | ||
|
||
MCHEM_SCEN_STOP_COMPLETE_STATES = ['CLEARED', 'ERROR'] | ||
MCHEM_SCEN_STOP_FAIL_STATES = ['ERROR'] | ||
MCHEM_SCEN_START_FAIL_STATES = ['COMPLETED', 'ABORTED', 'CLEARED', 'ERROR'] | ||
MCHEM_SCEN_RES_ID_KEY = 'reservation_id' | ||
MCHEM_SCEN_COMP_ID_KEY = 'competitor_id' | ||
MCHEM_SCEN_ID_KEY = 'scenario_id' | ||
MCHEM_SCEN_RADIO_MAP_KEY = 'srn_radio_mapping' | ||
MCHEM_SCEN_CYCLE_KEY = 'scenario_cycle' | ||
MCHEM_SCEN_STOP_KEY = 'stop_scenario' | ||
MCHEM_SCEN_STARTTIME_KEY = 'scenario_start_time' | ||
MCHEM_SCEN_STATUS_KEY = 'scenario_status' | ||
|
||
#SRN to CLI return codes | ||
CLI_RET_CODE_KEEPALIVE = 100 | ||
CLI_RET_CODE_SUCCESS = 200 | ||
CLI_RET_CODE_ERROR = 400 | ||
|
||
#Scenario Website | ||
WIKI_SCENARIO_LIST = 'http://sc2colosseum.pbworks.com/w/page/Scenarios' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import json | ||
import socket | ||
import os | ||
|
||
from colosseum_cli import colosseum_cli_constants as con | ||
|
||
|
||
def connect_and_send(json_data): | ||
""" | ||
Connects to the specfied socket and writes the json message. returns reponse | ||
Args: | ||
socket_path: | ||
json_str: | ||
Returns: | ||
returns up to 1024 bytes worth of response | ||
""" | ||
socket_path = con.SOCKET_PATH | ||
if os.environ.get(con.CLI_TEST_MODE_ENV) == 'TRUE': | ||
socket_path = con.TEST_SOCKET | ||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) | ||
ret = {} | ||
try: | ||
# Connect to server and send data | ||
sock.connect(socket_path) | ||
json_str = json.dumps(json_data) | ||
sock.sendall(bytes(json_str, "utf-8")) | ||
# Receive data from the server and shut down | ||
received = str(sock.recv(3276800), "utf-8") | ||
ret = json.loads(received) | ||
|
||
except OSError as msg: | ||
print("ERROR: colosseumcli can not connect to server.") | ||
finally: | ||
sock.close() | ||
return ret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import logging | ||
import re | ||
from cliff.command import Command | ||
from colosseum_cli import colosseum_cli_constants as con | ||
from colosseum_cli.colosseum_socket import connect_and_send | ||
|
||
|
||
def img_name_fmt(str): | ||
""" | ||
Validate img name for lxd container name restrictions | ||
Args: | ||
str: | ||
Returns: | ||
""" | ||
if (re.match(r'^[A-Za-z0-9-]*$', str) is None) or len(str) > 32: | ||
print("Image name may only contain alphanumeric and hyphen characters. ") | ||
print("Max length is 32 characters ") | ||
raise ValueError | ||
else: | ||
return str | ||
|
||
|
||
class container_snapshot(Command): | ||
"Create snapshot of the current container" | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
def get_parser(self, prog_name): | ||
parser = super(container_snapshot, self).get_parser(prog_name) | ||
parser.add_argument('filename', type=img_name_fmt, help='Name of the image to be saved. ' | ||
'May only contain alphanumeric and hyphen.' | ||
' Max length is 32 characters') | ||
return parser | ||
|
||
def take_action(self, parsed_args): | ||
""" | ||
Create json message to start a message | ||
:param parsed_args: | ||
:return: | ||
""" | ||
#print(parsed_args.filename) | ||
|
||
print('snapshotting the container to ' + parsed_args.filename + '.tar.gz') | ||
data_sent = { | ||
con.CLI_VER_KEY: con.CLI_MSG_VERSION, | ||
con.CLI_CMD_KEY: con.CLI_CMD_CTNR_SNAPSHOT, | ||
con.CLI_SNAPSHOT_FILE_KEY: parsed_args.filename, | ||
con.CLI_SNAPSHOT_PATH_KEY: con.CLI_SNAPSHOT_PATH | ||
} | ||
|
||
ret = connect_and_send(data_sent) | ||
print(ret['message']) | ||
self.log.debug('completed the snapshot') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
import logging | ||
import os | ||
import subprocess | ||
import time | ||
from cliff.command import Command | ||
from colosseum_cli import colosseum_cli_constants as con | ||
from colosseum_cli.colosseum_socket import connect_and_send | ||
from cliff.show import ShowOne | ||
from cliff.lister import Lister | ||
|
||
# | ||
# Start gps consumer on container | ||
# | ||
class gps_start(Command): | ||
"Start GPS feed." | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
def get_parser(self, prog_name): | ||
parser = super(gps_start, self).get_parser(prog_name) | ||
parser.add_argument('scenario_id', type=int, help='ID of gps scenario (same ID as RF scenario)') | ||
parser.add_argument('node_id', type=int, help='nodeid of the node\'s gps track to use (refer to the RF ' | ||
'scenario descriptions on pbworks to find the right nodeid)') | ||
return parser | ||
|
||
def take_action(self, parsed_args): | ||
self.log.debug("container received gps start command") | ||
|
||
self.log.debug("starting socat/unix socket (step 1 of 3)") | ||
socket_path = 'UNIX-LISTEN:' + con.CLI_CMD_GPS_UNIX_SOCKET | ||
process_socat = subprocess.Popen(['socat', socket_path, 'UDP4-SENDTO:127.0.0.1:5900'], | ||
shell=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) | ||
|
||
# hard wait of 1 second to let the UNIX socket settle | ||
# TODO: find a better way of checking the creation of the UNIX socket | ||
time.sleep(1) | ||
|
||
self.log.debug("setting permission on gps unix socket (step 2 of 3)") | ||
# give the UNIX socket 777 permissions; this gives the baremetal access to this UNIX socket | ||
os.chmod(con.CLI_CMD_GPS_UNIX_SOCKET, 0o777) | ||
|
||
self.log.debug("starting gpsd (step 3 of 3)") | ||
# note: since the srn's gps feeder hasn't started yet, the container's gpsd will be active but won't | ||
# produce any GPS coordinates | ||
process_gpsd = subprocess.Popen(['gpsd', 'udp://127.0.0.1:5900', '-n', '-N', '-S', '6000'], | ||
shell=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) | ||
|
||
# send 'gps start' message to srn; which will start the gps feed from baremetal | ||
data_sent = { | ||
con.CLI_VER_KEY: con.CLI_MSG_VERSION, | ||
con.CLI_CMD_KEY: con.CLI_CMD_GPS_START, | ||
con.CLI_CMD_GPS_RFID_KEY: parsed_args.scenario_id, | ||
con.CLI_CMD_GPS_NODEID_KEY: parsed_args.node_id | ||
} | ||
ret = connect_and_send(data_sent) | ||
|
||
if ret["status"] == con.CLI_RET_CODE_SUCCESS: | ||
self.log.debug("gps processes on srn started") | ||
print("\nGPS started. To check the gps feed in the container, run \'cgps 127.0.0.1:6000\'\n") | ||
else: | ||
self.log.error("gps processes on srn failed to start") | ||
|
||
|
||
# | ||
# Stop gps consumer on container | ||
# | ||
class gps_stop(Command): | ||
"Stop GPS feed." | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
#def get_parser(self, prog_name): | ||
# parser = super(gps_start, self).get_parser(prog_name) | ||
# parser.add_argument('filename', type=str, help='Name of the NMEA CSV input file.') | ||
# return parser | ||
|
||
def take_action(self, parsed_args): | ||
self.log.debug("container received gps stop command") | ||
|
||
# TODO: figure out a better/smarter way of killing the gpsd processes | ||
# the way the gpsd daemon is stopped is by issuing a "pkill -f" call. Which to say the least, is such a bad | ||
# way of doing things. The proper way would be to use the multiprocessing library to keep track of the | ||
# gps spawned processes from gps_start. Then issue a sigterm message to each process to gracefully shut it down. | ||
|
||
self.log.debug("stopping gpsd (step 1 of 2)") | ||
process1 = subprocess.Popen(['pkill', '-f', 'gpsd'], | ||
shell=False) | ||
|
||
self.log.debug("stopping socat/unix-socket (step 2 of 2)") | ||
process3 = subprocess.Popen(['pkill', '-f', 'socat'], | ||
shell=False) | ||
|
||
self.log.debug("all gps processes on container stopped") | ||
|
||
# send 'gps stop' message to srn; which will stop the gps feed from baremetal | ||
data_sent = { | ||
con.CLI_VER_KEY: con.CLI_MSG_VERSION, | ||
con.CLI_CMD_KEY: con.CLI_CMD_GPS_STOP | ||
} | ||
ret = connect_and_send(data_sent) | ||
|
||
if ret["status"] == con.CLI_RET_CODE_SUCCESS: | ||
self.log.debug("gps processes on srn stopped") | ||
print("\nGPS stopped\n") | ||
else: | ||
self.log.error("gps processes on srn failed to stop") | ||
|
||
# | ||
# Show gps scenario list on container | ||
# | ||
class gps_scenario_list(Command): | ||
"List GPS scenarios." | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
def take_action(self, parsed_args): | ||
print("\nThe GPS scenario id is the same as the RF scenario id (rf scenario list)\n") | ||
|
||
# | ||
# Get GPS scenario | ||
# | ||
class gps_info(Command): | ||
"Information on the active GPS scenario." | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
def take_action(self, parsed_args): | ||
|
||
self.log.debug('getting active GPS info') | ||
data_sent = { | ||
con.CLI_VER_KEY: con.CLI_MSG_VERSION, | ||
con.CLI_CMD_KEY: con.CLI_CMD_GPS_INFO | ||
} | ||
|
||
ret = connect_and_send(data_sent) | ||
|
||
if ret["status"] == con.CLI_RET_CODE_SUCCESS: | ||
data = ret["data"] | ||
gps_rf_scenario_id = data[con.CLI_CMD_GPS_RFID_KEY] | ||
gps_rf_node_id = data[con.CLI_CMD_GPS_NODEID_KEY] | ||
|
||
if (gps_rf_scenario_id is None) and (gps_rf_node_id is None): | ||
print("\nGPS is currently not running\n") | ||
else: | ||
print("\nGPS is currently running with RF scenario id " + str(gps_rf_scenario_id) + | ||
" and RF node id " + str(gps_rf_node_id) + "\n") |
Oops, something went wrong.