Exemplo n.º 1
0
 def get_tree_root_mac(self, db_topology):
     # the root of the tree should be the main switch.
     # we analyse the neighbors of this server:
     # - if we find one, we return it
     # - if we find several ones, we favor the ones in
     #   walt-net or walt-adm (thus we discard neighbors found from walt-out)
     # - if we still find several ones, we favor the ones which type is known
     #   as a switch
     server_mac = get_mac_address(const.WALT_INTF)
     unknown_neighbors = []
     for port, neighbor_mac, neighbor_port, confirmed in \
             db_topology.get_neighbors(server_mac):
         info = self.devices.get_complete_device_info(neighbor_mac)
         if info.ip is None:
             continue  # ignore this device
         if not (ip_in_walt_network(info.ip) or ip_in_walt_adm_network(info.ip)):
             continue  # ignore this device
         if info.type == 'unknown':
             unknown_neighbors.append(info.name)
             continue  # possibly the switch we are looking for
         if info.type == 'switch':
             return (True, neighbor_mac)  # Found it!
     # if we are here we did not find what we want
     out = MSG_UNKNOWN_TOPOLOGY
     if len(unknown_neighbors) > 0:
         out += format_sentence("Note: %s was(were) detected, but its(their) type is unknown.\n" +
                                "If it(one of them) is a switch, use:\n" +
                                "$ walt device config <device> type=switch\n",
                                unknown_neighbors, None, 'device', 'devices')
     return (False, out)
Exemplo n.º 2
0
 def reboot_nodes_after_image_change(self, requester, task_callback,
                                     image_fullname):
     nodes = self.nodes.get_nodes_using_image(image_fullname)
     if len(nodes) == 0:
         task_callback(None)  # nothing to do
         return
     requester.stdout.write(
         format_sentence('Trying to reboot %s using this image...\n',
                         [n.name for n in nodes], None, 'node', 'nodes'))
     self.nodes.reboot_nodes(requester, task_callback, nodes, False)
Exemplo n.º 3
0
 def applies_to_nodes(self, requester, device_infos, setting_name,
                      setting_value, all_settings):
     not_nodes = [di for di in device_infos if di.type != "node"]
     if len(not_nodes) > 0:
         msg = format_sentence(
             "Failed: %s is(are) not a() node(nodes), "
             "so it(they) does(do) not support the '" + setting_name +
             "' setting.\n", [d.name for d in not_nodes], None, 'Device',
             'Devices')
         requester.stderr.write(msg)
         return False
     return True
Exemplo n.º 4
0
 def applies_to_virtual_nodes(self, requester, device_infos, setting_name,
                              setting_value, all_settings):
     if not self.applies_to_nodes(requester, device_infos, setting_name,
                                  setting_value, all_settings):
         return False
     not_virtual_node = [di for di in device_infos if not di.virtual]
     if len(not_virtual_node) > 0:
         msg = format_sentence(
             "Failed: %s is(are) not virtual, "
             "so it(they) does(do) not support the '" + setting_name +
             "' setting.\n", [d.name for d in not_virtual_node], None,
             'Node', 'Nodes')
         requester.stderr.write(msg)
         return False
     return True
Exemplo n.º 5
0
 def applies_to_switches(self, requester, device_infos, setting_name,
                         setting_value, all_settings):
     # if we have another setting 'type=switch', then we are expecting unknown devices, and this
     # will be verified by the appropriate check for this other setting.
     if all_settings.get('type') == 'switch':
         return True  # ok for us
     not_switches = [di for di in device_infos if di.type != "switch"]
     if len(not_switches) > 0:
         msg = format_sentence(
             "Failed: %s is(are) not a() switch(switches), "
             "so '" + setting_name + "' setting cannot be applied.\n",
             [d.name for d in not_switches], None, 'Device', 'Devices')
         requester.stderr.write(msg)
         return False
     return True
Exemplo n.º 6
0
    def netsetup_handler(self, requester, device_set, netsetup_value):
        # Interpret the node set, some of them may be strict devices
        device_infos = self.devices.parse_device_set(requester, device_set)
        if device_infos is None:
            yield False

        # Check the node set
        not_nodes = [di for di in device_infos if di.type != "node"]
        if len(not_nodes) > 0:
            msg = format_sentence(
                "%s is(are) not a() node(nodes), "
                "so it(they) does(do) not support the 'netsetup' setting.\n",
                [d.name for d in not_nodes], None, 'Device', 'Devices')
            requester.stderr.write(msg)
            yield False

        # Interpret the value
        new_netsetup_state = None
        try:
            new_netsetup_state = NetSetup(netsetup_value)
        except ValueError:
            requester.stderr.write(
                "'%s' is not a valid setting value for netsetup." %
                (netsetup_value))
            yield False

        # Yield information that all things have ran correctly
        yield True

        # Effectively configure nodes
        for node_info in device_infos:
            if node_info.netsetup == new_netsetup_state:
                # skip this node: already configured
                continue
            # Update the database
            self.db.update("nodes",
                           "mac",
                           mac=node_info.mac,
                           netsetup=new_netsetup_state)
            # Update iptables
            do("iptables %(action)s WALT --source '%(ip)s' --jump ACCEPT" %
               dict(ip=node_info.ip,
                    action="--insert"
                    if new_netsetup_state == NetSetup.NAT else "--delete"))
            # Validate the modifications
            self.db.commit()
Exemplo n.º 7
0
def verify_compatibility_issue(image_store, requester, clonable_link,
                    ws_image_fullname, remote_image_fullname,
                    docker, target_node_models, nodes_manager, **args):
    ws_image = image_store[ws_image_fullname]
    if not ws_image.in_use:
        return  # no problem
    # there is a risk of overwritting the mounted ws image with
    # a target image that is incompatible.
    nodes = nodes_manager.get_nodes_using_image(ws_image_fullname)
    needed_models = set(node.model for node in nodes)
    image_compatible_models = set(target_node_models)
    incompatible_models = needed_models - image_compatible_models
    if len(incompatible_models) > 0:
        sentence = format_sentence(MSG_INCOMPATIBLE_MODELS, incompatible_models,
                        None, 'node model', 'node models')
        requester.stderr.write(sentence)
        return False    # give up
Exemplo n.º 8
0
 def includes_devices_not_owned(self, requester, device_set, warn):
     username = requester.get_username()
     if not username:
         return False    # client already disconnected, give up
     devices = self.parse_device_set(requester, device_set)
     if devices is None:
         return None
     not_owned = [d for d in devices
                  if not (d.type == "node" and
                          (d.image.startswith(username + '/') or d.image.startswith('waltplatform/'))
                          or d.type != "node")]
     if len(not_owned) == 0:
         return False
     else:
         if warn:
             requester.stderr.write(format_sentence(
                 'Warning: %s seems(seem) to be used by another(other) user(users).',
                 [d.name for d in not_owned], "No device", "Device", "Devices") + '\n')
         return True
Exemplo n.º 9
0
 def includes_devices_not_owned(self, requester, device_set, warn):
     username = requester.get_username()
     if not username:
         return False    # client already disconnected, give up
     devices = self.parse_device_set(requester, device_set)
     if devices is None:
         return None
     not_owned = [d for d in devices
                  if not (d.type == "node" and
                          (d.image.startswith(username + '/') or d.image.startswith('waltplatform/'))
                          or d.type != "node")]
     if len(not_owned) == 0:
         return False
     else:
         if warn:
             requester.stderr.write(format_sentence(
                 'Warning: %s seems(seem) to be used by another(other) user(users).',
                 [d.name for d in not_owned], "No device", "Device", "Devices") + '\n')
         return True
Exemplo n.º 10
0
    def netsetup_handler(self, requester, device_set, netsetup_value):
        # Interpret the node set, some of them may be strict devices
        device_infos = self.devices.parse_device_set(requester, device_set)
        if device_infos is None:
            yield False

        # Check the node set
        not_nodes = filter(lambda di: di.type != "node", device_infos)
        if len(not_nodes) > 0:
            msg = format_sentence("%s is(are) not a() node(nodes), "
                                  "so it(they) does(do) not support the 'netsetup' setting.\n",
                                  [d.name for d in not_nodes],
                                  None, 'Device', 'Devices')
            requester.stderr.write(msg)
            yield False

        # Interpret the value
        new_netsetup_state = None
        try:
            new_netsetup_state = NetSetup(netsetup_value)
        except ValueError:
            requester.stderr.write(
                "'%s' is not a valid setting value for netsetup." % (netsetup_value))
            yield False

        # Yield information that all things have ran correctly
        yield True

        # Effectively configure nodes
        for node_info in device_infos:
            if node_info.netsetup == new_netsetup_state:
                # skip this node: already configured
                continue
            # Update the database
            self.db.update("nodes", "mac", mac=node_info.mac, netsetup=new_netsetup_state)
            # Update iptables
            do("iptables %(action)s WALT --source '%(ip)s' --jump ACCEPT" %
               dict(ip=node_info.ip,
                    action="--insert" if new_netsetup_state == NetSetup.NAT else "--delete"))
            # Validate the modifications
            self.db.commit()
Exemplo n.º 11
0
 def set_image(self, requester, nodes, image_name):
     # if image tag is specified, let's get its fullname
     if image_name != 'default':
         image = self.store.get_user_image_from_name(requester, image_name)
         if image == None:
             return False
         image_compatible_models = set(image.get_node_models())
         node_models = set(node.model for node in nodes)
         incompatible_models = node_models - image_compatible_models
         if len(incompatible_models) > 0:
             sentence = format_sentence(MSG_INCOMPATIBLE_MODELS,
                                        incompatible_models, None,
                                        'node model', 'node models')
             requester.stderr.write(sentence)
             return False
         image_fullnames = {node.mac: image.fullname for node in nodes}
     else:
         image_fullnames = {}
         # since the 'default' keyword was specified, we might have to associate
         # different images depending on the type of each WalT node.
         # we compute the appropriate image fullname here.
         for node in nodes:
             image_fullnames[
                 node.mac] = self.store.get_default_image_fullname(
                     node.model)
     # let's update the database about which node is mounting what
     for node_mac, image_fullname in image_fullnames.items():
         self.db.update('nodes', 'mac', mac=node_mac, image=image_fullname)
     self.store.update_image_mounts(requester=requester)
     tftp.update(self.db, self.store)
     self.db.commit()
     self.dhcpd.update()
     # inform requester
     if image_name == 'default':
         sentence = MSG_BOOT_DEFAULT_IMAGE
     else:
         sentence = '%s will now boot ' + image_name + '.'
     requester.stdout.write(
         format_sentence_about_nodes(sentence, [n.name
                                                for n in nodes]) + '\n')
     return True
Exemplo n.º 12
0
 def set_image(self, requester, nodes, image_name):
     # if image tag is specified, let's get its fullname
     if image_name != 'default':
         image = self.store.get_user_image_from_name(requester, image_name)
         if image == None:
             return False
         image_compatible_models = set(image.get_node_models())
         node_models = set(node.model for node in nodes)
         incompatible_models = node_models - image_compatible_models
         if len(incompatible_models) > 0:
             sentence = format_sentence(MSG_INCOMPATIBLE_MODELS, incompatible_models,
                             None, 'node model', 'node models')
             requester.stderr.write(sentence)
             return False
         image_fullnames = { node.mac: image.fullname for node in nodes }
     else:
         image_fullnames = {}
         # since the 'default' keyword was specified, we might have to associate
         # different images depending on the type of each WalT node.
         # we compute the appropriate image fullname here.
         for node in nodes:
             image_fullnames[node.mac] = self.store.get_default_image_fullname(node.model)
     # let's update the database about which node is mounting what
     for node_mac, image_fullname in image_fullnames.items():
         self.db.update('nodes', 'mac',
                 mac=node_mac,
                 image=image_fullname)
     self.store.update_image_mounts(requester = requester)
     tftp.update(self.db)
     self.db.commit()
     self.dhcpd.update()
     # inform requester
     if image_name == 'default':
         sentence = MSG_BOOT_DEFAULT_IMAGE
     else:
         sentence = '%s will now boot ' + image_name + '.'
     requester.stdout.write(format_sentence_about_nodes(
         sentence, [n.name for n in nodes]) + '\n')
     return True
Exemplo n.º 13
0
 def get_device_config(self, requester, device_set):
     # ensure the device set is correct
     device_infos = self.server.devices.parse_device_set(
         requester, device_set)
     if device_infos is None:
         return  # issue already reported
     configs = defaultdict(lambda: defaultdict(list))
     for device_info in device_infos:
         # check device category
         secondary_category = None
         if device_info.type == 'unknown':
             category = 'unknown-devices'
         elif device_info.type == 'switch':
             category = 'switches'
         elif device_info.type == 'node':
             if device_info.virtual:
                 category = 'virtual-nodes'
                 secondary_category = 'nodes'
             else:
                 category = 'nodes'
         elif device_info.type == 'server':
             category = 'server'
         else:
             raise NotImplementedError(
                 'Unexpected device type in get_device_config().')
         # retrieve device settings
         settings = dict(device_info.conf)
         # add default value of unspecified settings
         for setting_name, setting_info in self.settings_table.items():
             if setting_info['category'] in (category, secondary_category) \
                     and setting_name not in settings:
                 settings[setting_name] = setting_info['default']
         # append to the list of devices having this same config
         sorted_config = tuple(sorted(settings.items()))
         configs[category][sorted_config].append(device_info.name)
     # print groups of devices having the same config
     parts = []
     for category, category_labels in (('nodes', ('Node', 'Nodes')),
                                       ('virtual-nodes', ('Virtual node',
                                                          'Virtual nodes')),
                                       ('switches', ('Switch', 'Switches')),
                                       ('server',
                                        None), ('unknown-devices',
                                                ('Unknown device',
                                                 'Unknown devices'))):
         if len(configs[category]) == 0:
             continue
         for sorted_config, device_names in configs[category].items():
             if category == 'server':
                 sentence_start = 'Server has'
             else:
                 sentence_start = format_sentence('%s has(have)',
                                                  device_names, None,
                                                  category_labels[0],
                                                  category_labels[1])
             if len(sorted_config) == 0:
                 parts.append(sentence_start +
                              ' no config option available.\n')
                 continue
             msg = sentence_start + ' the following config applied:\n'
             for setting_name, setting_value in sorted_config:
                 if setting_value is None:
                     pprinted_value = '<unspecified>'
                 else:
                     pprint = self.settings_table[setting_name].get(
                         'pretty_print')
                     if pprint is None:
                         pprinted_value = str(setting_value)
                     else:
                         pprinted_value = pprint(setting_value)
                 msg += '%s=%s\n' % (setting_name, pprinted_value)
             parts.append(msg)
     requester.stdout.write('\n\n'.join(parts) + '\n')