예제 #1
0
 def connect(self):
     try:
         self.omapi = Omapi(self.module.params['host'], self.module.params['port'], self.module.params['key_name'],
                            self.module.params['key'])
     except socket.error:
         e = get_exception()
         self.module.fail_json(msg="Unable to connect to OMAPI server: %s" % e)
예제 #2
0
 def __init__(self, omapi_key: str, ipv6: bool = False):
     self._omapi = Omapi(
         "127.0.0.1",
         7912 if ipv6 else 7911,
         b"omapi_key",
         omapi_key.encode("ascii"),
     )
예제 #3
0
 def connect(self):
     try:
         self.omapi = Omapi(self.module.params['host'], self.module.params['port'], self.module.params['key_name'],
                            self.module.params['key'])
     except binascii.Error:
         self.module.fail_json(msg="Unable to open OMAPI connection. 'key' is not a valid base64 key.")
     except OmapiError as e:
         self.module.fail_json(msg="Unable to open OMAPI connection. Ensure 'host', 'port', 'key' and 'key_name' "
                                   "are valid. Exception was: %s" % to_native(e))
     except socket.error as e:
         self.module.fail_json(msg="Unable to connect to OMAPI server: %s" % to_native(e))
예제 #4
0
 def connect(self):
     try:
         self.omapi = Omapi(self.module.params['host'], self.module.params['port'], self.module.params['key_name'],
                            self.module.params['key'])
     except binascii.Error:
         self.module.fail_json(msg="Unable to open OMAPI connection. 'key' is not a valid base64 key.")
     except OmapiError as e:
         self.module.fail_json(msg="Unable to open OMAPI connection. Ensure 'host', 'port', 'key' and 'key_name' "
                                   "are valid. Exception was: %s" % to_native(e))
     except socket.error as e:
         self.module.fail_json(msg="Unable to connect to OMAPI server: %s" % to_native(e))
예제 #5
0
class OmapiClient:
    """Client for the DHCP OMAPI."""

    def __init__(self, omapi_key: str, ipv6: bool = False):
        self._omapi = Omapi(
            "127.0.0.1",
            7912 if ipv6 else 7911,
            b"omapi_key",
            omapi_key.encode("ascii"),
        )

    def add_host(self, mac: str, ip: str):
        """Add a host mapping for a MAC."""
        name = self._name_from_mac(mac)
        self._omapi.add_host_supersede(ip, mac, name)

    def del_host(self, mac: str):
        """Remove a host mapping for a MAC."""
        self._omapi.del_host(mac)

    def update_host(self, mac: str, ip: str):
        """Update a host mapping for a MAC."""
        name = self._name_from_mac(mac)
        msg = OmapiMessage.open(b"host")
        msg.update_object({b"name": name})
        resp = self._omapi.query_server(msg)
        if resp.opcode != OMAPI_OP_UPDATE:
            raise OmapiError(f"Host not found: {name.decode('ascii')}")
        msg = OmapiMessage.update(resp.handle)
        msg.update_object({b"ip-address": pack_ip(ip)})
        resp = self._omapi.query_server(msg)
        if resp.opcode != OMAPI_OP_STATUS:
            raise OmapiError(
                f"Updating IP for host {name.decode('ascii')} to {ip} failed"
            )

    def _name_from_mac(self, mac: str) -> bytes:
        return mac.replace(":", "-").encode("ascii")
예제 #6
0
class OmapiHostManager:
    def __init__(self, module):
        self.module = module
        self.omapi = None
        self.connect()

    def connect(self):
        try:
            self.omapi = Omapi(self.module.params['host'], self.module.params['port'], self.module.params['key_name'],
                               self.module.params['key'])
        except socket.error:
            e = get_exception()
            self.module.fail_json(msg="Unable to connect to OMAPI server: %s" % e)

    def get_host(self, macaddr):
        msg = OmapiMessage.open(to_bytes("host", errors='surrogate_or_strict'))
        msg.obj.append((to_bytes("hardware-address", errors='surrogate_or_strict'), pack_mac(macaddr)))
        msg.obj.append((to_bytes("hardware-type", errors='surrogate_or_strict'), struct.pack("!I", 1)))
        response = self.omapi.query_server(msg)
        if response.opcode != OMAPI_OP_UPDATE:
            return None
        return response

    @staticmethod
    def unpack_facts(obj):
        result = dict(obj)
        if 'hardware-address' in result:
            result['hardware-address'] = unpack_mac(result['hardware-address'])

        if 'ip-address' in result:
            result['ip-address'] = unpack_ip(result['ip-address'])

        if 'hardware-type' in result:
            result['hardware-type'] = struct.unpack("!I", result['hardware-type'])

        return result

    def setup_host(self):
        if self.module.params['hostname'] is None or len(self.module.params['hostname']) == 0:
            self.module.fail_json(msg="name attribute could not be empty when adding or modifying host.")

        msg = None
        host_response = self.get_host(self.module.params['macaddr'])
        # If host was not found using macaddr, add create message
        if host_response is None:
            msg = OmapiMessage.open(to_bytes('host', errors='surrogate_or_strict'))
            msg.message.append(('create', struct.pack('!I', 1)))
            msg.message.append(('exclusive', struct.pack('!I', 1)))
            msg.obj.append(('hardware-address', pack_mac(self.module.params['macaddr'])))
            msg.obj.append(('hardware-type', struct.pack('!I', 1)))
            msg.obj.append(('name', self.module.params['hostname']))
            if self.module.params['ip'] is not None:
                msg.obj.append((to_bytes("ip-address", errors='surrogate_or_strict'), pack_ip(self.module.params['ip'])))

            stmt_join = ""
            if self.module.params['ddns']:
                stmt_join += 'ddns-hostname "{0}"; '.format(self.module.params['hostname'])

            try:
                if len(self.module.params['statements']) > 0:
                    stmt_join += "; ".join(self.module.params['statements'])
                    stmt_join += "; "
            except TypeError:
                e = get_exception()
                self.module.fail_json(msg="Invalid statements found: %s" % e)

            if len(stmt_join) > 0:
                msg.obj.append(('statements', stmt_join))

            try:
                response = self.omapi.query_server(msg)
                if response.opcode != OMAPI_OP_UPDATE:
                    self.module.fail_json(msg="Failed to add host, ensure authentication and host parameters "
                                              "are valid.")
                self.module.exit_json(changed=True, lease=self.unpack_facts(response.obj))
            except OmapiError:
                e = get_exception()
                self.module.fail_json(msg="OMAPI error: %s" % e)
        # Forge update message
        else:
            response_obj = self.unpack_facts(host_response.obj)
            fields_to_update = {}

            if to_bytes('ip-address', errors='surrogate_or_strict') not in response_obj or \
                            unpack_ip(response_obj[to_bytes('ip-address', errors='surrogate_or_strict')]) != self.module.params['ip']:
                fields_to_update['ip-address'] = pack_ip(self.module.params['ip'])

            # Name cannot be changed
            if 'name' not in response_obj or response_obj['name'] != self.module.params['hostname']:
                self.module.fail_json(msg="Changing hostname is not supported. Old was %s, new is %s. "
                                          "Please delete host and add new." %
                                          (response_obj['name'], self.module.params['hostname']))

            """
            # It seems statements are not returned by OMAPI, then we cannot modify them at this moment.
            if 'statements' not in response_obj and len(self.module.params['statements']) > 0 or \
                response_obj['statements'] != self.module.params['statements']:
                with open('/tmp/omapi', 'w') as fb:
                    for (k,v) in iteritems(response_obj):
                        fb.writelines('statements: %s %s\n' % (k, v))
            """
            if len(fields_to_update) == 0:
                self.module.exit_json(changed=False, lease=response_obj)
            else:
                msg = OmapiMessage.update(host_response.handle)
                msg.update_object(fields_to_update)

            try:
                response = self.omapi.query_server(msg)
                if response.opcode != OMAPI_OP_STATUS:
                    self.module.fail_json(msg="Failed to modify host, ensure authentication and host parameters "
                                              "are valid.")
                self.module.exit_json(changed=True)
            except OmapiError:
                e = get_exception()
                self.module.fail_json(msg="OMAPI error: %s" % e)

    def remove_host(self):
        try:
            self.omapi.del_host(self.module.params['macaddr'])
            self.module.exit_json(changed=True)
        except OmapiErrorNotFound:
            self.module.exit_json()
        except OmapiError:
            e = get_exception()
            self.module.fail_json(msg="OMAPI error: %s" % e)
예제 #7
0
    def post_init(self, **kwargs):
        # Get parameters from keyword arguments
        skip_modules = kwargs.get("skip_modules", False)
        skip_network = kwargs.get("skip_network", False)
        skip_ap = kwargs.get("skip_ap", False)
        # Extra options
        self.sdr_dev = kwargs.get("sdr_dev", "sdr0")
        #  self.lan_ip = kwargs.get("lan_ip", "192.168.13.1")
        self.lan_ip = kwargs.get("lan_ip", "10.0.0.1")
        #  gw_ip = kwargs.get("gw_ip", "134.226.55.211")
        gw_dev = kwargs.get("gw_dev", "eth0")
        ap_config_path = kwargs.get("ap_path",
                                    "/root/openwifi/hostapd-openwifi.conf")
        openwifi_path = kwargs.get("openwifi_path", "/root/openwifi")

        # Stop Network Manager
        bash("service network-manager stop")
        self._log("Stopped Network Manager")

        # If loading kernel modules
        if not skip_modules:
            fpga_dev_path = "/sys/bus/iio/devices/iio:device2"
            filter_file = "openwifi_ad9361_fir.ftr"

            # Load mac80211 kernel module
            bash("modprobe mac80211")
            self._log("Loaded 'mac80211' kernel module")

            # If the SDR kernel module is loaded
            if bool(bash("lsmod | grep sdr")):
                # Remove SDR kernel module
                bash("rmmod sdr")
                self._log("Removed 'sdr' kernel module")

            # List of custom kernel modules
            module_list = {
                "first_batch": ["xilinx_dma", "tx_intf", "ad9361_drv"],
                "second_batch":
                ["rx_intf", "openofdm_tx", "openofdm_rx", "xpu", "sdr"]
            }

            # Device configuration dictionary
            device_config = {
                "first_batch": {
                    "in_voltage_rf_bandwidth": "17500000",
                    "out_voltage_rf_bandwidth": "37500000",
                    "in_voltage_sampling_frequency": "40000000",
                    "out_voltage_sampling_frequency": "40000000",
                    "out_altvoltage0_RX_LO_frequency": "5240000000",
                    "out_altvoltage1_TX_LO_frequency": "5250000000"
                },
                "second_batch": {
                    "in_voltage_filter_fir_en": "1",
                    "out_voltage_filter_fir_en": "0",
                    "in_voltage0_gain_control_mode": "fast_attack",
                    "in_voltage1_gain_control_mode": "fast_attack",
                    "in_voltage0_hardwaregain": "70",
                    "in_voltage1_hardwaregain": "70",
                    "out_voltage0_hardwaregain": "89",
                    "out_voltage1_hardwaregain": "0"
                }
            }

            # Iterate over the first batch
            for submodule in module_list['first_batch']:
                # Check whether the module is loaded
                if bool(bash("lsmod | grep {0}".format(submodule))):
                    # Removing current version of the module
                    bash("rmmod {0}".format(submodule))
                # Installing new version of the module
                bash("insmod {0}/{1}.ko".format(openwifi_path, submodule))
                # Check installation of kernel module
                sleep(1)
                if not bash("lsmod | grep {0}".format(submodule)).code:
                    self._log("Loaded", submodule, "kernel module")

                else:
                    self._log("Not loaded", submodule, "kernel module")

            # Iterate over the first batch of parameters
            for parameter in device_config["first_batch"].keys():
                # Update the parameter value
                bash("echo {0} > {1}/{2}".format(
                    device_config["first_batch"][parameter], fpga_dev_path,
                    parameter))
                bash("sync")
                sleep(0.5)

            # Filter file string
            filter_str = "cat {0}/{1} > {2}/filter_fir_config"
            # Load filter response values
            bash(filter_str.format(openwifi_path, filter_file, fpga_dev_path))

            # Iterate over the second batch of parameters
            for parameter in device_config["second_batch"].keys():
                # Update the parameter value
                bash("echo {0} > {1}/{2}".format(
                    device_config["second_batch"][parameter], fpga_dev_path,
                    parameter))
                bash("sync")
                sleep(0.5)

            # Iterate over the second batch
            for submodule in module_list['second_batch']:
                # Check whether the module is loaded
                if bool(bash("lsmod | grep {0}".format(submodule))):
                    # Removing current version of the module
                    bash("rmmod {0}".format(submodule))

                # Installing new version of the module
                bash("insmod {0}/{1}.ko".format(openwifi_path, submodule))
                sleep(1)
                # Check installation of kernel module
                if not bash("lsmod | grep {0}".format(submodule)).code:
                    self._log("Loaded", submodule, "kernel module")

            # Sleep for 10 seconds and log event
            self._log("Waiting for configurations to take effect")
            sleep(10)
            self._log("Configured kernel modules and FPGA")

        # If configuring routing and networking
        if not skip_network:
            # Configure the SDR interface's IP
            bash("ifconfig {0} {1} netmask 255.255.255.0".format(
                self.sdr_dev, self.lan_ip))
            self._log("Set {0} interface IP's to: {1}".format(
                self.sdr_dev, self.lan_ip))

            # Set the default route through eth0
            #  bash("ip route add default via {0} dev eth0".format(gw_ip))
            bash("ip route add default dev {0}".format(gw_dev))
            #  self._log("Set default gateway to: {0}".format(gw_ip))
            self._log("Set default gateway to: {0}".format(gw_dev))

            # Sleep for 2 seconds and log event
            self._log("Configured routing and networking")

        # Stop DHCP server
        bash("service isc-dhcp-server stop")
        # Clear current leases
        bash("echo '' > /var/lib/dhcp/dhcpd.leases")
        # Start DHCP server
        bash("service isc-dhcp-server start")

        sleep(5)

        self._log("Restarted DHCP server")

        # Create a list of possible client IPs
        self.dhcp_pool = set(".".join(self.lan_ip.split(".")[:-1]) + "." +
                             str(x) for x in range(110, 200))

        # OMAPI Configuration parameters
        omapi_host = "127.0.0.1"
        omapi_port = 7911
        omapi_keyname = b"defomapi"
        omapi_key = b"SmR3+XVX95vDQ3SaZD1B7xTXYTcwNg/AZn9DAsJS" + \
            b"9oESudsTQ5bRMaSt bHPyOJchWlXF2Q6CuhSD70eTNl5hOg=="

        # Create OMAPI object
        self.omapi = Omapi(omapi_host, omapi_port, omapi_keyname, omapi_key)

        # If starting the access point
        if not skip_ap:
            # If there is a Host AP Daemon running in the background
            if bool(bash("ps -aux | grep [h]ostapd")):
                # Kill the process
                bash("killall hostapd")
                self._log("Stopped existing hostapd instances")

            # Run this 10 times or until hostapd starts
            for x in range(10):
                # Start Host AP Daemon in the background and log event
                apd = bash("hostapd -B {0}".format(ap_config_path)).code

                # If it worked
                if not apd:
                    break

                self._log("Trying to start the AP, #", x + 1)
                sleep(1)

            # If we could not configure the AP
            if apd:
                raise Exception("Could not configure AP")

            # Log event
            self._log("Configured access point")

        # TODO This ought to change in the future
        # List of currently support RAN slices
        self.ran_slice_list = [
            {
                "index": 0,
                "available": True
            },
            {
                "index": 1,
                "available": True
            },
            {
                "index": 2,
                "available": True
            },
            {
                "index": 3,
                "available": True
            },
        ]

        # Iterate over existing slices
        for ran_slice in self.ran_slice_list:
            # Set current slice index
            idx = bash("sdrctl dev {0} set slice_idx {1}".format(
                self.sdr_dev, ran_slice['index'])).code

            # Clear MAC addresses associated with slice
            cls = bash("sdrctl dev {0} set addr {1}".format(
                self.sdr_dev, "00000000")).code

            # Log event
            self._log("Failed clearing slice #" if cls else "Cleared slice #",
                      ran_slice["index"])

        # Sync all slices
        sync = bash("sdrctl dev {0} set slice_idx 4".format(self.sdr_dev)).code

        # Output status message and/or exit
        if not sync:
            self._log("Synchronised all RAN slices!")
        else:
            self._log("Failed synchronising RAN slices.")
            exit(10)
예제 #8
0
class opw_controller(base_controller):
    def post_init(self, **kwargs):
        # Get parameters from keyword arguments
        skip_modules = kwargs.get("skip_modules", False)
        skip_network = kwargs.get("skip_network", False)
        skip_ap = kwargs.get("skip_ap", False)
        # Extra options
        self.sdr_dev = kwargs.get("sdr_dev", "sdr0")
        #  self.lan_ip = kwargs.get("lan_ip", "192.168.13.1")
        self.lan_ip = kwargs.get("lan_ip", "10.0.0.1")
        #  gw_ip = kwargs.get("gw_ip", "134.226.55.211")
        gw_dev = kwargs.get("gw_dev", "eth0")
        ap_config_path = kwargs.get("ap_path",
                                    "/root/openwifi/hostapd-openwifi.conf")
        openwifi_path = kwargs.get("openwifi_path", "/root/openwifi")

        # Stop Network Manager
        bash("service network-manager stop")
        self._log("Stopped Network Manager")

        # If loading kernel modules
        if not skip_modules:
            fpga_dev_path = "/sys/bus/iio/devices/iio:device2"
            filter_file = "openwifi_ad9361_fir.ftr"

            # Load mac80211 kernel module
            bash("modprobe mac80211")
            self._log("Loaded 'mac80211' kernel module")

            # If the SDR kernel module is loaded
            if bool(bash("lsmod | grep sdr")):
                # Remove SDR kernel module
                bash("rmmod sdr")
                self._log("Removed 'sdr' kernel module")

            # List of custom kernel modules
            module_list = {
                "first_batch": ["xilinx_dma", "tx_intf", "ad9361_drv"],
                "second_batch":
                ["rx_intf", "openofdm_tx", "openofdm_rx", "xpu", "sdr"]
            }

            # Device configuration dictionary
            device_config = {
                "first_batch": {
                    "in_voltage_rf_bandwidth": "17500000",
                    "out_voltage_rf_bandwidth": "37500000",
                    "in_voltage_sampling_frequency": "40000000",
                    "out_voltage_sampling_frequency": "40000000",
                    "out_altvoltage0_RX_LO_frequency": "5240000000",
                    "out_altvoltage1_TX_LO_frequency": "5250000000"
                },
                "second_batch": {
                    "in_voltage_filter_fir_en": "1",
                    "out_voltage_filter_fir_en": "0",
                    "in_voltage0_gain_control_mode": "fast_attack",
                    "in_voltage1_gain_control_mode": "fast_attack",
                    "in_voltage0_hardwaregain": "70",
                    "in_voltage1_hardwaregain": "70",
                    "out_voltage0_hardwaregain": "89",
                    "out_voltage1_hardwaregain": "0"
                }
            }

            # Iterate over the first batch
            for submodule in module_list['first_batch']:
                # Check whether the module is loaded
                if bool(bash("lsmod | grep {0}".format(submodule))):
                    # Removing current version of the module
                    bash("rmmod {0}".format(submodule))
                # Installing new version of the module
                bash("insmod {0}/{1}.ko".format(openwifi_path, submodule))
                # Check installation of kernel module
                sleep(1)
                if not bash("lsmod | grep {0}".format(submodule)).code:
                    self._log("Loaded", submodule, "kernel module")

                else:
                    self._log("Not loaded", submodule, "kernel module")

            # Iterate over the first batch of parameters
            for parameter in device_config["first_batch"].keys():
                # Update the parameter value
                bash("echo {0} > {1}/{2}".format(
                    device_config["first_batch"][parameter], fpga_dev_path,
                    parameter))
                bash("sync")
                sleep(0.5)

            # Filter file string
            filter_str = "cat {0}/{1} > {2}/filter_fir_config"
            # Load filter response values
            bash(filter_str.format(openwifi_path, filter_file, fpga_dev_path))

            # Iterate over the second batch of parameters
            for parameter in device_config["second_batch"].keys():
                # Update the parameter value
                bash("echo {0} > {1}/{2}".format(
                    device_config["second_batch"][parameter], fpga_dev_path,
                    parameter))
                bash("sync")
                sleep(0.5)

            # Iterate over the second batch
            for submodule in module_list['second_batch']:
                # Check whether the module is loaded
                if bool(bash("lsmod | grep {0}".format(submodule))):
                    # Removing current version of the module
                    bash("rmmod {0}".format(submodule))

                # Installing new version of the module
                bash("insmod {0}/{1}.ko".format(openwifi_path, submodule))
                sleep(1)
                # Check installation of kernel module
                if not bash("lsmod | grep {0}".format(submodule)).code:
                    self._log("Loaded", submodule, "kernel module")

            # Sleep for 10 seconds and log event
            self._log("Waiting for configurations to take effect")
            sleep(10)
            self._log("Configured kernel modules and FPGA")

        # If configuring routing and networking
        if not skip_network:
            # Configure the SDR interface's IP
            bash("ifconfig {0} {1} netmask 255.255.255.0".format(
                self.sdr_dev, self.lan_ip))
            self._log("Set {0} interface IP's to: {1}".format(
                self.sdr_dev, self.lan_ip))

            # Set the default route through eth0
            #  bash("ip route add default via {0} dev eth0".format(gw_ip))
            bash("ip route add default dev {0}".format(gw_dev))
            #  self._log("Set default gateway to: {0}".format(gw_ip))
            self._log("Set default gateway to: {0}".format(gw_dev))

            # Sleep for 2 seconds and log event
            self._log("Configured routing and networking")

        # Stop DHCP server
        bash("service isc-dhcp-server stop")
        # Clear current leases
        bash("echo '' > /var/lib/dhcp/dhcpd.leases")
        # Start DHCP server
        bash("service isc-dhcp-server start")

        sleep(5)

        self._log("Restarted DHCP server")

        # Create a list of possible client IPs
        self.dhcp_pool = set(".".join(self.lan_ip.split(".")[:-1]) + "." +
                             str(x) for x in range(110, 200))

        # OMAPI Configuration parameters
        omapi_host = "127.0.0.1"
        omapi_port = 7911
        omapi_keyname = b"defomapi"
        omapi_key = b"SmR3+XVX95vDQ3SaZD1B7xTXYTcwNg/AZn9DAsJS" + \
            b"9oESudsTQ5bRMaSt bHPyOJchWlXF2Q6CuhSD70eTNl5hOg=="

        # Create OMAPI object
        self.omapi = Omapi(omapi_host, omapi_port, omapi_keyname, omapi_key)

        # If starting the access point
        if not skip_ap:
            # If there is a Host AP Daemon running in the background
            if bool(bash("ps -aux | grep [h]ostapd")):
                # Kill the process
                bash("killall hostapd")
                self._log("Stopped existing hostapd instances")

            # Run this 10 times or until hostapd starts
            for x in range(10):
                # Start Host AP Daemon in the background and log event
                apd = bash("hostapd -B {0}".format(ap_config_path)).code

                # If it worked
                if not apd:
                    break

                self._log("Trying to start the AP, #", x + 1)
                sleep(1)

            # If we could not configure the AP
            if apd:
                raise Exception("Could not configure AP")

            # Log event
            self._log("Configured access point")

        # TODO This ought to change in the future
        # List of currently support RAN slices
        self.ran_slice_list = [
            {
                "index": 0,
                "available": True
            },
            {
                "index": 1,
                "available": True
            },
            {
                "index": 2,
                "available": True
            },
            {
                "index": 3,
                "available": True
            },
        ]

        # Iterate over existing slices
        for ran_slice in self.ran_slice_list:
            # Set current slice index
            idx = bash("sdrctl dev {0} set slice_idx {1}".format(
                self.sdr_dev, ran_slice['index'])).code

            # Clear MAC addresses associated with slice
            cls = bash("sdrctl dev {0} set addr {1}".format(
                self.sdr_dev, "00000000")).code

            # Log event
            self._log("Failed clearing slice #" if cls else "Cleared slice #",
                      ran_slice["index"])

        # Sync all slices
        sync = bash("sdrctl dev {0} set slice_idx 4".format(self.sdr_dev)).code

        # Output status message and/or exit
        if not sync:
            self._log("Synchronised all RAN slices!")
        else:
            self._log("Failed synchronising RAN slices.")
            exit(10)

    def create_slice(self, **kwargs):
        # Extract parameters from keyword arguments
        s_id = str(kwargs.get('s_id', None))
        s_mac = str(kwargs.get('s_mac', None))
        i_sln = int(kwargs.get("slice", {}).get('number', 0))

        # If the MAC address is invalid
        if not s_mac or s_mac is None:
            return False, "Malformatted MAC address:" + str(s_mac)

        # Iterate over the current slices
        for sid in self.s_ids:
            # Check whether the entered MAC address is already being used
            if self.s_ids[sid] and (s_mac == self.s_ids[sid]['mac']):
                # Return error
                return False, "MAC address already associated to slice: " + sid

        # Check whether the slice number is valid
        if i_sln not in [x['index'] for x in self.ran_slice_list]:
            # If not, return error
            return False, "Invalid slice number:" + str(i_sln)

        # Check whether there an available slice
        elif not self.ran_slice_list[i_sln]['available']:
            # If not, return error
            return False, "Slice #" + str(i_sln) + " is not available."

        # Check whether the given MAC address has a current DHCP lease
        try:
            # Try to check it
            self.omapi.lookup_by_host(mac=s_mac)

        # If it doesn't work, great
        except OmapiErrorNotFound:
            pass

        # Otherwise, clear it
        else:
            self.omapi.del_host(s_mac)

        # Get the first available IP address
        lease_ip = self.dhcp_pool.pop()

        # Add host to the DHCP subnet
        try:
            self.omapi.add_host(lease_ip, s_mac)

        # If if failed
        except OmapiError:
            # Report to the hyperstrator
            return False, "DHCP lease creation failed."

        # Log event
        self._log("Set", s_mac, "IP to:", lease_ip)

        # Get the slice configuration parameters
        i_start = int(kwargs.get("slice", {}).get('start', 0))
        i_end = int(kwargs.get("slice", {}).get('end', 49999))
        i_total = int(kwargs.get("slice", {}).get('total', 50000))

        # Set the slice in question
        bash("sdrctl dev {0} set slice_idx {1}".format(self.sdr_dev, i_sln))

        # Set the slice configuration
        bash("sdrctl dev {0} set slice_start {1}".format(
            self.sdr_dev, i_start))
        bash("sdrctl dev {0} set slice_end {1}".format(self.sdr_dev, i_end))
        bash("sdrctl dev {0} set slice_total {1}".format(
            self.sdr_dev, i_total))

        # Sync all commands
        sync = bash("sdrctl dev {0} set slice_idx 4".format(self.sdr_dev)).code

        # Log event
        self._log("Set slice", i_sln, " start/end/total to", i_start, "/",
                  i_end, "/", i_total)

        # Set the slice in question
        bash("sdrctl dev {0} set slice_idx {1}".format(self.sdr_dev, i_sln))

        print(s_mac)
        # Get MAC address associated with service and map it to 32 bits
        s_mac_32 = s_mac.replace(":", "")[4:]

        print(s_mac_32)

        # Add MAC address to SDRCTL
        sla = bash("sdrctl dev {0} set addr {1}".format(
            self.sdr_dev, s_mac_32)).code

        # Sync all commands
        sync = bash("sdrctl dev {0} set slice_idx 4".format(self.sdr_dev)).code

        if sla or sync:
            return False, "Slice creation failed."

        # Iterate over the slice slice
        for i, x in enumerate(self.ran_slice_list):
            # If matching the slice number
            if x["index"] == i_sln:
                # Toggle flag
                self.ran_slice_list[i]['available'] = False

        # Create a slice entry
        self.s_ids[s_id] = {
            "mac": s_mac,
            "ip": lease_ip,
            "slice": {
                "number": i_sln,
                "start": i_start,
                "end": i_end,
                "total": i_total
            }
        }

        # Log event
        self._log("Created slice", s_id)

        return True, {"s_id": s_id, "destination": lease_ip}

    def request_slice(self, **kwargs):
        # Extract parameters from keyword arguments
        s_id = kwargs.get('s_id', None)

        # Container to told the requested information
        msg = {}
        # Iterate over all slices
        for virtual_radio in self.s_ids:
            # If requesting info about a specific S_ID but it is not a match
            if s_id and s_id != virtual_radio:
                continue

            # Log event
            self._log("Found virtual radio:", virtual_radio)

            # Append this information to the output dictionary
            msg[s_id] = {
                "mac": self.s_ids[virtual_radio]["mac"],
                "ip": self.s_ids[virtual_radio]["ip"],
                "slice": self.s_ids[virtual_radio]["slice"]
            }

        # Return flag and dictionary in case positive
        return (False, "Virtual radio missing") if \
            (s_id and not msg) else (True, msg)

    def update_slice(self, **kwargs):
        # Extract parameters from keyword arguments
        s_id = kwargs.get('s_id', None)

        # Return state
        return True, "This is a stub"

    def delete_slice(self, **kwargs):
        # Extract parameters from keyword arguments
        s_id = kwargs.get('s_id', None)

        # Get the client's MAC address
        s_mac = self.s_ids[s_id]["mac"]
        # Get the slice number
        i_sln = self.s_ids[s_id]["slice"]["number"]

        # Remove host from the DHCP subnet
        self.omapi.del_host(s_mac)

        # Set the slice in question
        bash("sdrctl dev {0} set slice_idx {1}".format(self.sdr_dev, i_sln))

        # Try to clear the slice
        cls = bash("sdrctl dev {0} set addr {1}".format(
            self.sdr_dev, "00000000")).code

        # If the last command failed
        if cls:
            return False, "Could not remove MAC from slice #" + str(i_lsn)

        # Set the default slice configuration
        s = bash("sdrctl dev {0} set slice_start {1}".format(self.sdr_dev,
                                                             0)).code
        e = bash("sdrctl dev {0} set slice_end {1}".format(
            self.sdr_dev, 49999)).code
        t = bash("sdrctl dev {0} set slice_total {1}".format(
            self.sdr_dev, 50000)).code

        # Sync all commands
        sync = bash("sdrctl dev {0} set slice_idx 4".format(self.sdr_dev)).code

        # If any of the precious commands failed
        if any([s, e, t, sync]):
            return False, "Failed reverting slice to default parameters."

        # Iterate over the slice slice
        for i, x in enumerate(self.ran_slice_list):
            # If matching the slice number
            if x["index"] == i_sln:
                # Toggle flag
                self.ran_slice_list[i]['available'] = True

        # Return state
        return True, {"s_id": s_id}
예제 #9
0
class OmapiHostManager:
    def __init__(self, module):
        self.module = module
        self.omapi = None
        self.connect()

    def connect(self):
        try:
            self.omapi = Omapi(self.module.params['host'], self.module.params['port'], self.module.params['key_name'],
                               self.module.params['key'])
        except binascii.Error:
            self.module.fail_json(msg="Unable to open OMAPI connection. 'key' is not a valid base64 key.")
        except OmapiError as e:
            self.module.fail_json(msg="Unable to open OMAPI connection. Ensure 'host', 'port', 'key' and 'key_name' "
                                      "are valid. Exception was: %s" % to_native(e))
        except socket.error as e:
            self.module.fail_json(msg="Unable to connect to OMAPI server: %s" % to_native(e))

    def get_host(self, macaddr):
        msg = OmapiMessage.open(to_bytes("host", errors='surrogate_or_strict'))
        msg.obj.append((to_bytes("hardware-address", errors='surrogate_or_strict'), pack_mac(macaddr)))
        msg.obj.append((to_bytes("hardware-type", errors='surrogate_or_strict'), struct.pack("!I", 1)))
        response = self.omapi.query_server(msg)
        if response.opcode != OMAPI_OP_UPDATE:
            return None
        return response

    @staticmethod
    def unpack_facts(obj):
        result = dict(obj)
        if 'hardware-address' in result:
            result['hardware-address'] = unpack_mac(result['hardware-address'])

        if 'ip-address' in result:
            result['ip-address'] = unpack_ip(result['ip-address'])

        if 'hardware-type' in result:
            result['hardware-type'] = struct.unpack("!I", result['hardware-type'])

        return result

    def setup_host(self):
        if self.module.params['hostname'] is None or len(self.module.params['hostname']) == 0:
            self.module.fail_json(msg="name attribute could not be empty when adding or modifying host.")

        msg = None
        host_response = self.get_host(self.module.params['macaddr'])
        # If host was not found using macaddr, add create message
        if host_response is None:
            msg = OmapiMessage.open(to_bytes('host', errors='surrogate_or_strict'))
            msg.message.append(('create', struct.pack('!I', 1)))
            msg.message.append(('exclusive', struct.pack('!I', 1)))
            msg.obj.append(('hardware-address', pack_mac(self.module.params['macaddr'])))
            msg.obj.append(('hardware-type', struct.pack('!I', 1)))
            msg.obj.append(('name', self.module.params['hostname']))
            if self.module.params['ip'] is not None:
                msg.obj.append((to_bytes("ip-address", errors='surrogate_or_strict'), pack_ip(self.module.params['ip'])))

            stmt_join = ""
            if self.module.params['ddns']:
                stmt_join += 'ddns-hostname "{0}"; '.format(self.module.params['hostname'])

            try:
                if len(self.module.params['statements']) > 0:
                    stmt_join += "; ".join(self.module.params['statements'])
                    stmt_join += "; "
            except TypeError as e:
                self.module.fail_json(msg="Invalid statements found: %s" % to_native(e),
                                      exception=traceback.format_exc())

            if len(stmt_join) > 0:
                msg.obj.append(('statements', stmt_join))

            try:
                response = self.omapi.query_server(msg)
                if response.opcode != OMAPI_OP_UPDATE:
                    self.module.fail_json(msg="Failed to add host, ensure authentication and host parameters "
                                              "are valid.")
                self.module.exit_json(changed=True, lease=self.unpack_facts(response.obj))
            except OmapiError as e:
                self.module.fail_json(msg="OMAPI error: %s" % to_native(e), exception=traceback.format_exc())
        # Forge update message
        else:
            response_obj = self.unpack_facts(host_response.obj)
            fields_to_update = {}

            if to_bytes('ip-address', errors='surrogate_or_strict') not in response_obj or \
                            unpack_ip(response_obj[to_bytes('ip-address', errors='surrogate_or_strict')]) != self.module.params['ip']:
                fields_to_update['ip-address'] = pack_ip(self.module.params['ip'])

            # Name cannot be changed
            if 'name' not in response_obj or response_obj['name'] != self.module.params['hostname']:
                self.module.fail_json(msg="Changing hostname is not supported. Old was %s, new is %s. "
                                          "Please delete host and add new." %
                                          (response_obj['name'], self.module.params['hostname']))

            """
            # It seems statements are not returned by OMAPI, then we cannot modify them at this moment.
            if 'statements' not in response_obj and len(self.module.params['statements']) > 0 or \
                response_obj['statements'] != self.module.params['statements']:
                with open('/tmp/omapi', 'w') as fb:
                    for (k,v) in iteritems(response_obj):
                        fb.writelines('statements: %s %s\n' % (k, v))
            """
            if len(fields_to_update) == 0:
                self.module.exit_json(changed=False, lease=response_obj)
            else:
                msg = OmapiMessage.update(host_response.handle)
                msg.update_object(fields_to_update)

            try:
                response = self.omapi.query_server(msg)
                if response.opcode != OMAPI_OP_STATUS:
                    self.module.fail_json(msg="Failed to modify host, ensure authentication and host parameters "
                                              "are valid.")
                self.module.exit_json(changed=True)
            except OmapiError as e:
                self.module.fail_json(msg="OMAPI error: %s" % to_native(e), exception=traceback.format_exc())

    def remove_host(self):
        try:
            self.omapi.del_host(self.module.params['macaddr'])
            self.module.exit_json(changed=True)
        except OmapiErrorNotFound:
            self.module.exit_json()
        except OmapiError as e:
            self.module.fail_json(msg="OMAPI error: %s" % to_native(e), exception=traceback.format_exc())
예제 #10
0
 def close(self):
     NacOmapi.instance = None
     Omapi.close(self)