| Jeremy Mordkoff | 6f07e6f | 2016-09-07 18:56:51 -0400 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | |
| 3 | import argparse |
| 4 | import logging |
| 5 | import os |
| 6 | import sys |
| 7 | |
| 8 | import gi |
| 9 | gi.require_version('RwcalYang', '1.0') |
| 10 | gi.require_version('RwCal', '1.0') |
| 11 | gi.require_version('RwLog', '1.0') |
| 12 | |
| 13 | import rift.cal.server as cal_server |
| 14 | import rift.cal.client as cal_client |
| 15 | import rift.cal.utils as cal_utils |
| 16 | import rift.rwcal.cloudsim.lxc as lxc |
| 17 | import rift.rwcal.cloudsim.lvm as lvm |
| 18 | import rift.rwcal.cloudsim.shell as shell |
| 19 | |
| 20 | from prettytable import PrettyTable |
| 21 | |
| 22 | |
| 23 | START_PARSER = "start" |
| 24 | STOP_PARSER = "stop" |
| 25 | CLEAN_PARSER = "clean" |
| 26 | FCLEAN_PARSER = "force-clean" |
| 27 | IMAGE_PARSER = "image-create" |
| 28 | STATUS_PARSER = "status" |
| 29 | |
| 30 | |
| 31 | class CloudsimOperations(cal_utils.CloudSimCalMixin): |
| 32 | def __init__(self, args): |
| 33 | super().__init__() |
| 34 | self.log = cal_utils.Logger( |
| 35 | daemon_mode=False, |
| 36 | log_name="Parser", |
| 37 | log_level=logging.getLevelName(args.log_level)).logger |
| 38 | |
| 39 | self.args = args |
| 40 | self.operations = cal_server.CloudsimServerOperations(self.log) |
| 41 | self.client = cal_client.CloudsimClient(self.log) |
| 42 | self._cal, self._account = None, None |
| 43 | |
| 44 | @property |
| 45 | def log_file(self): |
| 46 | return cal_utils.Logger.LOG_FILE |
| 47 | |
| 48 | @cal_utils.check_and_create_bridge |
| 49 | def start_server(self): |
| 50 | self.operations.start_server(foreground=self.args.foreground) |
| 51 | |
| 52 | @cal_utils.check_and_create_bridge |
| 53 | def stop_server(self): |
| 54 | self.operations.stop_server() |
| 55 | |
| 56 | @cal_utils.check_and_create_bridge |
| 57 | def clean_resources(self): |
| 58 | """Clean all resource using rest APIs. """ |
| 59 | self.operations.clean_server(images=self.args.all) |
| 60 | |
| 61 | @cal_utils.check_and_create_bridge |
| 62 | def upload_image(self): |
| 63 | """Onboard image to cloudsim server.""" |
| 64 | self.client.upload_image(self.args.location, name=self.args.name) |
| 65 | |
| 66 | def force_clean_resources(self): |
| 67 | """Force clean up all resource. """ |
| 68 | self.log.info("Cleaning up logs") |
| 69 | shell.command("rm -f {}".format(self.log_file)) |
| 70 | |
| 71 | self.log.info("Cleaning up PID file") |
| 72 | shell.command("rm -f {}".format(self.operations.PID_FILE)) |
| 73 | |
| 74 | try: |
| 75 | self.log.info("Purging LXC resources") |
| 76 | for container in lxc.containers(): |
| 77 | lxc.stop(container) |
| 78 | |
| 79 | for container in lxc.containers(): |
| 80 | lxc.destroy(container) |
| 81 | |
| 82 | lvm.destroy('rift') |
| 83 | |
| 84 | except shell.ProcessError: |
| 85 | self.log.exception("Unable to purge resources. Trying a force clean now.") |
| 86 | lxc.force_clean() |
| 87 | |
| 88 | @cal_utils.check_and_create_bridge |
| 89 | def show_status(self): |
| 90 | |
| 91 | cld_tbl = PrettyTable(['PID', 'Status', 'Log file']) |
| 92 | |
| 93 | pid = self.operations.pid |
| 94 | if pid: |
| 95 | cld_tbl.add_row([pid, "RUNNING", self.log_file]) |
| 96 | else: |
| 97 | cld_tbl.add_row(["-", "STOPPED", self.log_file]) |
| 98 | |
| 99 | print ("Cloudsim server:") |
| 100 | print (cld_tbl) |
| 101 | |
| 102 | if not pid: |
| 103 | return |
| 104 | |
| 105 | # Images |
| 106 | img_tbl = PrettyTable(['ID', 'Name', 'Format']) |
| 107 | vlink_tbl = PrettyTable([ |
| 108 | 'ID', 'Name', 'Bridge Name', 'State', 'Subnet', 'Ports', "IPs"]) |
| 109 | vdu_tbl = PrettyTable([ |
| 110 | 'ID', 'Name', 'LXC Name', 'IP', 'State', 'Ports', "VLink ID"]) |
| 111 | |
| 112 | |
| 113 | images = self.client.images |
| 114 | if images: |
| 115 | for image in images: |
| 116 | img_tbl.add_row([image.id, image.name, image.disk_format]) |
| 117 | |
| 118 | print ("Images:") |
| 119 | print (img_tbl) |
| 120 | |
| 121 | vlinks = self.client.vlinks |
| 122 | if vlinks: |
| 123 | for vlink in vlinks: |
| 124 | |
| 125 | ports, ips = [], [] |
| 126 | for cp in vlink.connection_points: |
| 127 | ports.append("{} ({})".format(cp.name, cp.connection_point_id)) |
| 128 | ips.append(cp.ip_address) |
| 129 | |
| 130 | vlink_tbl.add_row([ |
| 131 | vlink.virtual_link_id, |
| 132 | vlink.name, |
| 133 | vlink.name[:15], |
| 134 | vlink.state, |
| 135 | vlink.subnet, |
| 136 | "\n".join(ports), |
| 137 | "\n".join(ips)]) |
| 138 | |
| 139 | print ("Vlink:") |
| 140 | print (vlink_tbl) |
| 141 | |
| 142 | |
| 143 | lxc_to_ip = lxc.ls_info() |
| 144 | def get_lxc_name(ip): |
| 145 | for lxc_name, ips in lxc_to_ip.items(): |
| 146 | if str(ip) in ips: |
| 147 | return lxc_name |
| 148 | |
| 149 | return "" |
| 150 | |
| 151 | vdus = self.client.vdus |
| 152 | if vdus: |
| 153 | for vdu in vdus: |
| 154 | ports, links = [], [] |
| 155 | for cp in vdu.connection_points: |
| 156 | ports.append("{} ({})".format(cp.name, cp.ip_address)) |
| 157 | links.append(cp.virtual_link_id) |
| 158 | |
| 159 | vdu_tbl.add_row([ |
| 160 | vdu.vdu_id, vdu.name, get_lxc_name(vdu.public_ip), vdu.public_ip, |
| 161 | vdu.state, "\n".join(ports), "\n".join(links)]) |
| 162 | |
| 163 | print ("VDU:") |
| 164 | print (vdu_tbl) |
| 165 | |
| 166 | |
| 167 | def parse(arguments): |
| 168 | parser = argparse.ArgumentParser(description=__doc__, |
| 169 | formatter_class=argparse.RawDescriptionHelpFormatter) |
| 170 | parser.add_argument( |
| 171 | '--log-level', '-l', |
| 172 | default="WARNING", |
| 173 | type=str, |
| 174 | choices=["INFO", "DEBUG", "WARNING", "ERROR"], |
| 175 | help="Set log level, defaults to warning and above.") |
| 176 | |
| 177 | subparsers = parser.add_subparsers() |
| 178 | |
| 179 | start_parser = subparsers.add_parser(START_PARSER, help="Start the server") |
| 180 | start_parser.add_argument( |
| 181 | '--foreground', "-f", |
| 182 | help="Run the server in the foreground. The logs are sent to console.", |
| 183 | default=False, |
| 184 | action="store_true") |
| 185 | start_parser.set_defaults(which=START_PARSER) |
| 186 | |
| 187 | stop_parser = subparsers.add_parser(STOP_PARSER, help="Stop the server") |
| 188 | stop_parser.set_defaults(which=STOP_PARSER) |
| 189 | |
| 190 | clean_parser = subparsers.add_parser( |
| 191 | CLEAN_PARSER, |
| 192 | help="Clean LXC resources. By default all resources except " + \ |
| 193 | "images are cleared.") |
| 194 | clean_parser.add_argument( |
| 195 | '--all', '-a', |
| 196 | help="Cleans up all resources including images", |
| 197 | default=False, |
| 198 | action="store_true") |
| 199 | clean_parser.set_defaults(which=CLEAN_PARSER) |
| 200 | |
| 201 | fclean_parser = subparsers.add_parser( |
| 202 | FCLEAN_PARSER, |
| 203 | help="Force clean all lxc resources") |
| 204 | fclean_parser.set_defaults(which=FCLEAN_PARSER) |
| 205 | |
| 206 | image_parser = subparsers.add_parser(IMAGE_PARSER, help="Upload images") |
| 207 | image_parser.add_argument( |
| 208 | '--name', '-n', |
| 209 | help="(Optional) Name of the image") |
| 210 | image_parser.add_argument( |
| 211 | '--location', '-l', |
| 212 | help="Image location. If name is not specified the basename of " + \ |
| 213 | "the image path is used.", |
| 214 | required=True) |
| 215 | image_parser.set_defaults(which=IMAGE_PARSER) |
| 216 | |
| 217 | show_parser = subparsers.add_parser( |
| 218 | STATUS_PARSER, |
| 219 | help="Shows the current status of LXC") |
| 220 | show_parser.set_defaults(which=STATUS_PARSER) |
| 221 | |
| 222 | args = parser.parse_args(arguments) |
| 223 | |
| 224 | return args |
| 225 | |
| 226 | |
| 227 | def main(args): |
| 228 | |
| 229 | args = parse(args) |
| 230 | |
| 231 | operations = CloudsimOperations(args) |
| 232 | |
| 233 | if args.which == START_PARSER: |
| 234 | operations.start_server() |
| 235 | elif args.which == STOP_PARSER: |
| 236 | operations.stop_server() |
| 237 | elif args.which == FCLEAN_PARSER: |
| 238 | operations.force_clean_resources() |
| 239 | elif args.which == CLEAN_PARSER: |
| 240 | operations.clean_resources() |
| 241 | elif args.which == IMAGE_PARSER: |
| 242 | operations.upload_image() |
| 243 | elif args.which == STATUS_PARSER: |
| 244 | operations.show_status() |
| 245 | |
| 246 | |
| 247 | if __name__ == "__main__": |
| 248 | main(sys.argv[1:]) |