Esempio n. 1
0
def network_delete(network):
    """Delete network.

    If the network does not exist, a NotFoundError will be raised.

    If the network is connected to nodes or headnodes, or there are pending
    network actions involving it, a BlockedError will be raised.
    """
    auth_backend = get_auth_backend()

    network = _must_find(model.Network, network)

    if network.owner is None:
        auth_backend.require_admin()
    else:
        auth_backend.require_project_access(network.owner)

    if len(network.attachments) != 0:
        raise BlockedError("Network still connected to nodes")
    if network.hnics:
        raise BlockedError("Network still connected to headnodes")
    if len(network.scheduled_nics) != 0:
        raise BlockedError("There are pending actions on this network")
    if network.allocated:
        get_network_allocator().free_network_id(network.network_id)

    db.session.delete(network)
    db.session.commit()
Esempio n. 2
0
File: api.py Progetto: henn/hil
def network_delete(network):
    """Delete network.

    If the network does not exist, a NotFoundError will be raised.

    If the network is connected to nodes or headnodes, or there are pending
    network actions involving it, a BlockedError will be raised.
    """
    auth_backend = get_auth_backend()

    network = _must_find(model.Network, network)

    if network.creator is None:
        auth_backend.require_admin()
    else:
        auth_backend.require_project_access(network.creator)

    if len(network.attachments) != 0:
        raise BlockedError("Network still connected to nodes")
    if network.hnics:
        raise BlockedError("Network still connected to headnodes")
    if len(network.scheduled_nics) != 0:
        raise BlockedError("There are pending actions on this network")
    if network.allocated:
        get_network_allocator().free_network_id(network.network_id)

    db.session.delete(network)
    db.session.commit()
Esempio n. 3
0
def network_create(network, owner, access, net_id):
    """Create a network.

    If the network with that name already exists, a DuplicateError will be
    raised.

    If the combination of owner, access, and net_id is illegal, a
    BadArgumentError will be raised.

    If network ID allocation was requested, and the network cannot be
    allocated (due to resource exhaustion), an AllocationError will be raised.

    Pass 'admin' as owner for an administrator-owned network.  Pass '' as
    access for a publicly accessible network.  Pass '' as net_id if you wish
    to use the HaaS's network-id allocation pool.

    Details of the various combinations of network attributes are in
    docs/networks.md
    """
    auth_backend = get_auth_backend()
    _assert_absent(model.Network, network)

    # Check authorization and legality of arguments, and find correct 'access'
    # and 'owner'
    if owner != "admin":
        owner = _must_find(model.Project, owner)
        auth_backend.require_project_access(owner)
        # Project-owned network
        if access != owner.label:
            raise BadArgumentError(
                "Project-owned networks must be accessible by the owner.")
        if net_id != "":
            raise BadArgumentError(
                "Project-owned networks must use network ID allocation")
        access = [_must_find(model.Project, access)]
    else:
        # Administrator-owned network
        auth_backend.require_admin()
        owner = None
        if access == "":
            access = []
        else:
            access = [_must_find(model.Project, access)]

    # Allocate net_id, if requested
    if net_id == "":
        net_id = get_network_allocator().get_new_network_id()
        if net_id is None:
            raise AllocationError('No more networks')
        allocated = True
    else:
        if not get_network_allocator().validate_network_id(net_id):
            raise BadArgumentError("Invalid net_id")
        allocated = False

    network = model.Network(owner, access, allocated, net_id, network)
    db.session.add(network)
    db.session.commit()
Esempio n. 4
0
def network_create(network, owner, access, net_id):
    """Create a network.

    If the network with that name already exists, a DuplicateError will be
    raised.

    If the combination of owner, access, and net_id is illegal, a
    BadArgumentError will be raised.

    If network ID allocation was requested, and the network cannot be
    allocated (due to resource exhaustion), an AllocationError will be raised.

    Pass 'admin' as owner for an administrator-owned network.  Pass '' as
    access for a publicly accessible network.  Pass '' as net_id if you wish
    to use the HaaS's network-id allocation pool.

    Details of the various combinations of network attributes are in
    docs/networks.md
    """
    auth_backend = get_auth_backend()
    _assert_absent(model.Network, network)

    # Check authorization and legality of arguments, and find correct 'access'
    # and 'owner'
    if owner != "admin":
        owner = _must_find(model.Project, owner)
        auth_backend.require_project_access(owner)
        # Project-owned network
        if access != owner.label:
            raise BadArgumentError(
                "Project-owned networks must be accessible by the owner.")
        if net_id != "":
            raise BadArgumentError(
                "Project-owned networks must use network ID allocation")
        access = [_must_find(model.Project, access)]
    else:
        # Administrator-owned network
        auth_backend.require_admin()
        owner = None
        if access == "":
            access = []
        else:
            access = [_must_find(model.Project, access)]

    # Allocate net_id, if requested
    if net_id == "":
        net_id = get_network_allocator().get_new_network_id()
        if net_id is None:
            raise AllocationError('No more networks')
        allocated = True
    else:
        if not get_network_allocator().validate_network_id(net_id):
            raise BadArgumentError("Invalid net_id")
        allocated = False

    network = model.Network(owner, access, allocated, net_id, network)
    db.session.add(network)
    db.session.commit()
Esempio n. 5
0
def create_db():
    """Create and populate the initial database.

    The database connection must have been previously initialzed via `haas.model.init_db`.
    """
    with app.app_context():
        db.create_all()
        for head in paths.keys():
            # Record the version of each branch. Each extension which uses the
            # database will have its own branch.
            stamp(revision=head)
        get_network_allocator().populate()
        db.session.commit()
Esempio n. 6
0
def create_db():
    """Create and populate the initial database.

    The database connection must have been previously initialzed via
    `haas.model.init_db`.
    """
    with app.app_context():
        db.create_all()
        for head in _expected_heads():
            # Record the version of each branch. Each extension which uses the
            # database will have its own branch.
            db.session.execute(
                AlembicVersion.insert().values(version_num=head))
        get_network_allocator().populate()
        db.session.commit()
Esempio n. 7
0
def show_network(network):
    """Show details of a network.

    Returns a JSON object representing a network. See `docs/rest_api.md`
    for a full description of the output.
    """
    allocator = get_network_allocator()
    auth_backend = get_auth_backend()

    network = _must_find(model.Network, network)

    if network.access:
        authorized = False
        for proj in network.access:
            authorized = authorized or auth_backend.have_project_access(proj)

        if not authorized:
            raise AuthorizationError("You do not have access to this network.")

    result = {
        'name': network.label,
        'channels': allocator.legal_channels_for(network.network_id),
    }
    if network.owner is None:
        result['owner'] = 'admin'
    else:
        result['owner'] = network.owner.label

    if network.access:
        result['access'] = [p.label for p in network.access]
    else:
        result['access'] = None

    return json.dumps(result, sort_keys=True)
Esempio n. 8
0
def show_network(network):
    """Show details of a network.

    Returns a JSON object representing a network. See `docs/rest_api.md`
    for a full description of the output.
    """
    allocator = get_network_allocator()
    auth_backend = get_auth_backend()

    network = _must_find(model.Network, network)

    if network.access is not None:
        auth_backend.require_project_access(network.access)

    result = {
        'name': network.label,
        'channels': allocator.legal_channels_for(network.network_id),
    }
    if network.creator is None:
        result['creator'] = 'admin'
    else:
        result['creator'] = network.creator.label

    if network.access is not None:
        result['access'] = network.access.label

    return json.dumps(result, sort_keys=True)
Esempio n. 9
0
def show_network(network):
    """Show details of a network.

    Returns a JSON object representing a network. See `docs/rest_api.md`
    for a full description of the output.
    """
    allocator = get_network_allocator()
    auth_backend = get_auth_backend()

    network = _must_find(model.Network, network)

    if network.access:
        authorized = False
        for proj in network.access:
            authorized = authorized or auth_backend.have_project_access(proj)

        if not authorized:
            raise AuthorizationError("You do not have access to this network.")

    result = {
        'name': network.label,
        'channels': allocator.legal_channels_for(network.network_id),
    }
    if network.owner is None:
        result['owner'] = 'admin'
    else:
        result['owner'] = network.owner.label

    if network.access:
        result['access'] = [p.label for p in network.access]
    else:
        result['access'] = None

    return json.dumps(result, sort_keys=True)
Esempio n. 10
0
File: api.py Progetto: lokI8/haas
def show_network(network):
    """Show details of a network.

    Returns a JSON object representing a network.
    The object will have at least the following fields:
        * "name", the name/label of the network (string).
        * "creator", the name of the project which created the network, or
          "admin", if it was created by an administrator.
        * "channels", a list of channels to which the network may be attached.
    It may also have the fields:
        * "access" -- if this is present, it is the name of the project which
          has access to the network. Otherwise, the network is public.
    """
    db = model.Session()
    allocator = get_network_allocator()

    network = _must_find(db, model.Network, network)
    result = {
        'name': network.label,
        'channels': allocator.legal_channels_for(db, network.network_id),
    }
    if network.creator is None:
        result['creator'] = 'admin'
    else:
        result['creator'] = network.creator.label

    if network.access is not None:
        result['access'] = network.access.label

    return json.dumps(result)
Esempio n. 11
0
File: api.py Progetto: henn/hil
def show_network(network):
    """Show details of a network.

    Returns a JSON object representing a network. See `docs/rest_api.md`
    for a full description of the output.
    """
    allocator = get_network_allocator()
    auth_backend = get_auth_backend()

    network = _must_find(model.Network, network)

    if network.access is not None:
        auth_backend.require_project_access(network.access)

    result = {
        'name': network.label,
        'channels': allocator.legal_channels_for(network.network_id),
    }
    if network.creator is None:
        result['creator'] = 'admin'
    else:
        result['creator'] = network.creator.label

    if network.access is not None:
        result['access'] = network.access.label

    return json.dumps(result, sort_keys=True)
Esempio n. 12
0
File: api.py Progetto: lokI8/haas
def network_delete(network):
    """Delete network.

    If the network does not exist, a NotFoundError will be raised.
    """
    db = model.Session()
    network = _must_find(db, model.Network, network)

    if len(network.attachments) != 0:
        raise BlockedError("Network still connected to nodes")
    if network.hnics:
        raise BlockedError("Network still connected to headnodes")
    if len(network.scheduled_nics) != 0:
        raise BlockedError("There are pending actions on this network")
    if network.allocated:
        get_network_allocator().free_network_id(db, network.network_id)

    db.delete(network)
    db.commit()
Esempio n. 13
0
File: model.py Progetto: lokI8/haas
def init_db(create=False, uri=None):
    """Start up the DB connection.

    If `create` is True, this will generate the schema for the database, and
    perform initial population of tables.

    `uri` is the uri to use for the databse. If it is None, the uri from the
    config file will be used.
    """

    if uri == None:
        uri = cfg.get('database', 'uri')

    engine = create_engine(uri)
    if create:
        Base.metadata.create_all(engine)
    Session.configure(bind=engine)
    if create:
        get_network_allocator().populate(Session())
Esempio n. 14
0
def additional_db():
    """ Populated database with additional objects needed for testing.

    The database setup in initial_db is required to remain static as
    a starting point for database migrations so any changes needed for
    testing should be made in additional_db.
    """

    initial_db()

    switch = db.session.query(Switch).filter_by(label="stock_switch_0").one()
    manhattan = db.session.query(Project).filter_by(label="manhattan").one()
    runway = db.session.query(Project).filter_by(label="runway").one()

    with app.app_context():
        for node_label in ['runway_node_0', 'runway_node_1',
                           'manhattan_node_0', 'manhattan_node_1']:

            node = db.session.query(Node).filter_by(label=node_label).one()
            nic = db.session.query(Nic).filter_by(owner=node,
                                                  label='boot-nic').one()

            port = Port('connected_port_0', switch)
            port.nic = nic
            nic.port = port

        networks = [
            {
                'owner': None,
                'access': [manhattan, runway],
                'allocated': False,
                'network_id': 'manhattan_runway_provider_chan',
                'label': 'manhattan_runway_provider',
            },
            {
                'owner': manhattan,
                'access': [manhattan, runway],
                'allocated': True,
                'label': 'manhattan_runway_pxe',
            },
        ]

        for net in networks:
            if net['allocated']:
                net['network_id'] = \
                    get_network_allocator().get_new_network_id()
            db.session.add(Network(**net))
            db.session.add(node)

        db.session.add(switch)
        node = db.session.query(Node).filter_by(label='runway_node_0').one()
        db.session.add(Metadata('EK', 'pk', node))
        db.session.add(Metadata('SHA256', 'b5962d8173c14e60259211bcf25d1263c36'
                                'e0ad7da32ba9d07b224eac1834813', node))
        db.session.commit()
Esempio n. 15
0
File: server.py Progetto: lokI8/haas
def validate_state():
    """Do some sanity checking before kicking things off. In particular:

    * Make sure we have a network allocator

    (More checks may be added in the future).

    If any of the checks fail, ``validate_state`` aborts the program.
    """
    if get_network_allocator() is None:
        sys.exit("ERROR: No network allocator registered; make sure your "
                 "haas.cfg loads an extension which provides the network "
                 "allocator.")
Esempio n. 16
0
def network_create(network, creator, access, net_id):
    """Create a network.

    If the network with that name already exists, a DuplicateError will be
    raised.

    If the combination of creator, access, and net_id is illegal, a
    BadArgumentError will be raised.

    If network ID allocation was requested, and the network cannot be
    allocated (due to resource exhaustion), an AllocationError will be raised.

    Pass 'admin' as creator for an administrator-owned network.  Pass '' as
    access for a publicly accessible network.  Pass '' as net_id if you wish
    to use the HaaS's network-id allocation pool.

    Details of the various combinations of network attributes are in
    docs/networks.md
    """
    db = local.db
    _assert_absent(model.Network, network)

    # Check legality of arguments, and find correct 'access' and 'creator'
    if creator != "admin":
        # Project-owned network
        if access != creator:
            raise BadArgumentError("Project-created networks must be accessed only by that project.")
        if net_id != "":
            raise BadArgumentError("Project-created networks must use network ID allocation")
        creator = _must_find(model.Project, creator)
        access = _must_find(model.Project, access)
    else:
        # Administrator-owned network
        creator = None
        if access == "":
            access = None
        else:
            access = _must_find(model.Project, access)

    # Allocate net_id, if requested
    if net_id == "":
        net_id = get_network_allocator().get_new_network_id(db)
        if net_id is None:
            raise AllocationError('No more networks')
        allocated = True
    else:
        allocated = False

    network = model.Network(creator, access, allocated, net_id, network)
    db.add(network)
    db.commit()
Esempio n. 17
0
def additional_db():
    """ Populated database with additional objects needed for testing.

    The database setup in initial_db is required to remain static as
    a starting point for database migrations so any changes needed for
    testing should be made in additional_db.
    """

    initial_db()

    switch = db.session.query(Switch).filter_by(label="stock_switch_0").one()
    manhattan = db.session.query(Project).filter_by(label="manhattan").one()
    runway = db.session.query(Project).filter_by(label="runway").one()

    with app.app_context():
        for node_label in ['runway_node_0', 'runway_node_1',
                           'manhattan_node_0', 'manhattan_node_1']:

            node = db.session.query(Node).filter_by(label=node_label).one()
            nic = db.session.query(Nic).filter_by(owner=node,
                                                  label='boot-nic').one()

            port = Port('connected_port_0', switch)
            port.nic = nic
            nic.port = port

        networks = [
            {
                'owner': None,
                'access': [manhattan, runway],
                'allocated': False,
                'network_id': 'manhattan_runway_provider_chan',
                'label': 'manhattan_runway_provider',
            },
            {
                'owner': manhattan,
                'access': [manhattan, runway],
                'allocated': True,
                'label': 'manhattan_runway_pxe',
            },
        ]

        for net in networks:
            if net['allocated']:
                net['network_id'] = \
                    get_network_allocator().get_new_network_id()
            db.session.add(Network(**net))
            db.session.add(node)

        db.session.add(switch)
        db.session.commit()
Esempio n. 18
0
File: server.py Progetto: saacg/hil
def validate_state():
    """Do some sanity checking before kicking things off. In particular:

    * Make sure we have extensions loaded for:
      * a network allocator
      * an auth backend

    (More checks may be added in the future).

    If any of the checks fail, ``validate_state`` aborts the program.
    """
    if get_network_allocator() is None:
        sys.exit("ERROR: No network allocator registered; make sure your "
                 "haas.cfg loads an extension which provides the network "
                 "allocator.")
    if auth.get_auth_backend() is None:
        sys.exit("ERROR: No authentication/authorization backend registered; "
                 "make sure your haas.cfg loads an extension which provides "
                 "the auth backend.")
Esempio n. 19
0
def validate_state():
    """Do some sanity checking before kicking things off. In particular:

    * Make sure we have extensions loaded for:
      * a network allocator
      * an auth backend

    (More checks may be added in the future).

    If any of the checks fail, ``validate_state`` aborts the program.
    """
    if get_network_allocator() is None:
        sys.exit("ERROR: No network allocator registered; make sure your "
                 "haas.cfg loads an extension which provides the network "
                 "allocator.")
    if auth.get_auth_backend() is None:
        sys.exit("ERROR: No authentication/authorization backend registered; "
                 "make sure your haas.cfg loads an extension which provides "
                 "the auth backend.")
Esempio n. 20
0
File: api.py Progetto: henn/hil
def node_connect_network(node, nic, network, channel=None):
    """Connect a physical NIC to a network, on channel.

    If channel is ``None``, use the allocator default.

    Raises ProjectMismatchError if the node is not in a project, or if the
    project does not have access rights to the given network.

    Raises BlockedError if there is a pending network action, or if the network
    is already attached to the nic, or if the channel is in use.

    Raises BadArgumentError if the channel is invalid for the network.
    """

    def _have_attachment(nic, query):
        """Return whether there are any attachments matching ``query`` for ``nic``.

        ``query`` should an argument suitable to pass to db.query(...).filter
        """
        return model.NetworkAttachment.query.filter(
            model.NetworkAttachment.nic == nic,
            query,
        ).count() != 0

    auth_backend = get_auth_backend()

    node = _must_find(model.Node, node)
    nic = _must_find_n(node, model.Nic, nic)
    network = _must_find(model.Network, network)

    if not node.project:
        raise ProjectMismatchError("Node not in project")
    auth_backend.require_project_access(node.project)

    project = node.project

    allocator = get_network_allocator()

    if nic.port is None:
        raise NotFoundError("No port is connected to given nic.")

    if nic.current_action:
        raise BlockedError("A networking operation is already active on the nic.")

    if (network.access is not None) and (network.access is not project):
        raise ProjectMismatchError("Project does not have access to given network.")

    if _have_attachment(nic, model.NetworkAttachment.network == network):
        raise BlockedError("The network is already attached to the nic.")

    if channel is None:
        channel = allocator.get_default_channel()

    if _have_attachment(nic, model.NetworkAttachment.channel == channel):
        raise BlockedError("The channel is already in use on the nic.")

    if not allocator.is_legal_channel_for(channel, network.network_id):
        raise BadArgumentError("Channel %r, is not legal for this network." %
                               channel)

    db.session.add(model.NetworkingAction(nic=nic,
                                          new_network=network,
                                          channel=channel))
    db.session.commit()
    return '', 202
Esempio n. 21
0
def db(request):
    session = fresh_database(request)
    # Create a couple projects:
    runway = model.Project("runway")
    manhattan = model.Project("manhattan")
    for proj in [runway, manhattan]:
        session.add(proj)

    # ...including at least one with nothing in it:
    session.add(model.Project('empty-project'))

    # ...A variety of networks:

    networks = [
        {
            'creator': None,
            'access': None,
            'allocated': True,
            'label': 'stock_int_pub',
        },
        {
            'creator': None,
            'access': None,
            'allocated': False,
            'network_id': 'ext_pub_chan',
            'label': 'stock_ext_pub',
        },
        {
            # For some tests, we want things to initial be attached to a
            # network. This one serves that purpose; using the others would
            # interfere with some of the network_delete tests.
            'creator': None,
            'access': None,
            'allocated': True,
            'label': 'pub_default',
        },
        {
            'creator': runway,
            'access': runway,
            'allocated': True,
            'label': 'runway_pxe'
        },
        {
            'creator': None,
            'access': runway,
            'allocated': False,
            'network_id': 'runway_provider_chan',
            'label': 'runway_provider',
        },
        {
            'creator': manhattan,
            'access': manhattan,
            'allocated': True,
            'label': 'manhattan_pxe'
        },
        {
            'creator': None,
            'access': manhattan,
            'allocated': False,
            'network_id': 'manhattan_provider_chan',
            'label': 'manhattan_provider',
        },
    ]

    for net in networks:
        if net['allocated']:
            net['network_id'] = \
                get_network_allocator().get_new_network_id(session)
        session.add(model.Network(**net))

    # ... Two switches. One of these is just empty, for testing deletion:
    session.add(MockSwitch(label='empty-switch',
                           hostname='empty',
                           username='******',
                           password='******',
                           type=MockSwitch.api_name))

    # ... The other we'll actually attach stuff to for other tests:
    switch = MockSwitch(label="stock_switch_0",
                        hostname='stock',
                        username='******',
                        password='******',
                        type=MockSwitch.api_name)

    # ... Some free ports:
    session.add(model.Port('free_port_0', switch))
    session.add(model.Port('free_port_1', switch))

    # ... Some nodes (with projets):
    nodes = [
        {'label': 'runway_node_0', 'project': runway},
        {'label': 'runway_node_1', 'project': runway},
        {'label': 'manhattan_node_0', 'project': manhattan},
        {'label': 'manhattan_node_1', 'project': manhattan},
        {'label': 'free_node_0', 'project': None},
        {'label': 'free_node_1', 'project': None},
    ]
    for node_dict in nodes:
        obm=MockObm(type=MockObm.api_name,
                    host=node_dict['label'],
                    user='******',
                    password='******')
        node = model.Node(label=node_dict['label'], obm=obm)
        node.project = node_dict['project']
        session.add(model.Nic(node, label='boot-nic', mac_addr='Unknown'))

        # give it a nic that's attached to a port:
        port_nic = model.Nic(node, label='nic-with-port', mac_addr='Unknown')
        port = model.Port(node_dict['label'] + '_port', switch)
        port.nic = port_nic

    # ... Some headnodes:
    headnodes = [
        {'label': 'runway_headnode_on', 'project': runway, 'on': True},
        {'label': 'runway_headnode_off', 'project': runway, 'on': False},
        {'label': 'runway_manhattan_on', 'project': manhattan, 'on': True},
        {'label': 'runway_manhattan_off', 'project': manhattan, 'on': False},
    ]
    for hn_dict in headnodes:
        headnode = model.Headnode(hn_dict['project'],
                                  hn_dict['label'],
                                  'base-headnode')
        headnode.dirty = not hn_dict['on']
        hnic = model.Hnic(headnode, 'pxe')
        session.add(hnic)

        # Connect them to a network, so we can test detaching.
        hnic = model.Hnic(headnode, 'public')
        hnic.network = session.query(model.Network)\
            .filter_by(label='pub_default').one()


    # ... and at least one node with no nics (useful for testing delete):
    obm=MockObm(type=MockObm.api_name,
        host='hostname',
        user='******',
        password='******')
    session.add(model.Node(label='no_nic_node', obm=obm))

    session.commit()
    return session
Esempio n. 22
0
def initial_db():
    """Populates the database with a useful set of objects.

    This allows us to avoid some boilerplate in tests which need a few objects
    in the database in order to work.

    Is static to allow database migrations to be tested, if new objects need
    to be added they should be included in additional_db not initial_db.

    Note that this fixture requires the use of the following extensions:

        - haas.ext.switches.mock
        - haas.ext.obm.mock
    """
    for required_extension in 'haas.ext.switches.mock', 'haas.ext.obm.mock':
        assert required_extension in sys.modules, \
            "The 'initial_db' fixture requires the extension %r" % \
            required_extension

    from haas.ext.switches.mock import MockSwitch
    from haas.ext.obm.mock import MockObm

    with app.app_context():
        # Create a couple projects:
        runway = Project("runway")
        manhattan = Project("manhattan")
        for proj in [runway, manhattan]:
            db.session.add(proj)

        # ...including at least one with nothing in it:
        db.session.add(Project('empty-project'))

        # ...A variety of networks:

        networks = [
            {
                'owner': None,
                'access': [],
                'allocated': True,
                'label': 'stock_int_pub',
            },
            {
                'owner': None,
                'access': [],
                'allocated': False,
                'network_id': 'ext_pub_chan',
                'label': 'stock_ext_pub',
            },
            {
                # For some tests, we want things to initially be attached to a
                # network. This one serves that purpose; using the others would
                # interfere with some of the network_delete tests.
                'owner': None,
                'access': [],
                'allocated': True,
                'label': 'pub_default',
            },
            {
                'owner': runway,
                'access': [runway],
                'allocated': True,
                'label': 'runway_pxe'
            },
            {
                'owner': None,
                'access': [runway],
                'allocated': False,
                'network_id': 'runway_provider_chan',
                'label': 'runway_provider',
            },
            {
                'owner': manhattan,
                'access': [manhattan],
                'allocated': True,
                'label': 'manhattan_pxe'
            },
            {
                'owner': None,
                'access': [manhattan],
                'allocated': False,
                'network_id': 'manhattan_provider_chan',
                'label': 'manhattan_provider',
            },
        ]

        for net in networks:
            if net['allocated']:
                net['network_id'] = \
                    get_network_allocator().get_new_network_id()
            db.session.add(Network(**net))

        # ... Two switches. One of these is just empty, for testing deletion:
        db.session.add(MockSwitch(label='empty-switch',
                                  hostname='empty',
                                  username='******',
                                  password='******',
                                  type=MockSwitch.api_name))

        # ... The other we'll actually attach stuff to for other tests:
        switch = MockSwitch(label="stock_switch_0",
                            hostname='stock',
                            username='******',
                            password='******',
                            type=MockSwitch.api_name)

        # ... Some free ports:
        db.session.add(Port('free_port_0', switch))
        db.session.add(Port('free_port_1', switch))

        # ... Some nodes (with projets):
        nodes = [
            {'label': 'runway_node_0', 'project': runway},
            {'label': 'runway_node_1', 'project': runway},
            {'label': 'manhattan_node_0', 'project': manhattan},
            {'label': 'manhattan_node_1', 'project': manhattan},
            {'label': 'free_node_0', 'project': None},
            {'label': 'free_node_1', 'project': None},
        ]
        for node_dict in nodes:
            obm = MockObm(type=MockObm.api_name,
                          host=node_dict['label'],
                          user='******',
                          password='******')
            node = Node(label=node_dict['label'], obm=obm)
            node.project = node_dict['project']
            db.session.add(Nic(node, label='boot-nic', mac_addr='Unknown'))

            # give it a nic that's attached to a port:
            port_nic = Nic(node, label='nic-with-port', mac_addr='Unknown')
            port = Port(node_dict['label'] + '_port', switch)
            port.nic = port_nic

        # ... Some headnodes:
        headnodes = [
            {'label': 'runway_headnode_on',
             'project': runway,
             'on': True},
            {'label': 'runway_headnode_off',
             'project': runway,
             'on': False},
            {'label': 'runway_manhattan_on',
             'project': manhattan,
             'on': True},
            {'label': 'runway_manhattan_off',
             'project': manhattan,
             'on': False},
        ]
        for hn_dict in headnodes:
            headnode = Headnode(hn_dict['project'],
                                hn_dict['label'],
                                'base-headnode')
            headnode.dirty = not hn_dict['on']
            hnic = Hnic(headnode, 'pxe')
            db.session.add(hnic)

            # Connect them to a network, so we can test detaching.
            hnic = Hnic(headnode, 'public')
            hnic.network = Network.query \
                .filter_by(label='pub_default').one()

        # ... and at least one node with no nics (useful for testing delete):
        obm = MockObm(type=MockObm.api_name,
                      host='hostname',
                      user='******',
                      password='******')
        db.session.add(Node(label='no_nic_node', obm=obm))

        db.session.commit()
Esempio n. 23
0
def node_connect_network(node, nic, network, channel=None):
    """Connect a physical NIC to a network, on channel.

    If channel is ``None``, use the allocator default.

    Raises ProjectMismatchError if the node is not in a project, or if the
    project does not have access rights to the given network.

    Raises BlockedError if there is a pending network action, or if the network
    is already attached to the nic, or if the channel is in use.

    Raises BadArgumentError if the channel is invalid for the network.
    """
    def _have_attachment(nic, query):
        """Return whether there are any attachments matching ``query`` for ``nic``.

        ``query`` should an argument suitable to pass to db.query(...).filter
        """
        return model.NetworkAttachment.query.filter(
            model.NetworkAttachment.nic == nic,
            query,
        ).count() != 0

    auth_backend = get_auth_backend()

    node = _must_find(model.Node, node)
    nic = _must_find_n(node, model.Nic, nic)
    network = _must_find(model.Network, network)

    if not node.project:
        raise ProjectMismatchError("Node not in project")
    auth_backend.require_project_access(node.project)

    project = node.project

    allocator = get_network_allocator()

    if nic.port is None:
        raise NotFoundError("No port is connected to given nic.")

    if nic.current_action:
        raise BlockedError(
            "A networking operation is already active on the nic.")

    if (network.access) and (project not in network.access):
        raise ProjectMismatchError(
            "Project does not have access to given network.")

    if _have_attachment(nic, model.NetworkAttachment.network == network):
        raise BlockedError("The network is already attached to the nic.")

    if channel is None:
        channel = allocator.get_default_channel()

    if _have_attachment(nic, model.NetworkAttachment.channel == channel):
        raise BlockedError("The channel is already in use on the nic.")

    if not allocator.is_legal_channel_for(channel, network.network_id):
        raise BadArgumentError("Channel %r, is not legal for this network." %
                               channel)

    db.session.add(
        model.NetworkingAction(nic=nic, new_network=network, channel=channel))
    db.session.commit()
    return '', 202
Esempio n. 24
0
def initial_db():
    """Populates the database with a useful set of objects.

    This allows us to avoid some boilerplate in tests which need a few objects
    in the database in order to work.

    Is static to allow database migrations to be tested, if new objects need
    to be added they should be included in additional_db not initial_db.

    Note that this fixture requires the use of the following extensions:

        - haas.ext.switches.mock
        - haas.ext.obm.mock
    """
    for required_extension in 'haas.ext.switches.mock', 'haas.ext.obm.mock':
        assert required_extension in sys.modules, \
            "The 'initial_db' fixture requires the extension %r" % \
            required_extension

    from haas.ext.switches.mock import MockSwitch
    from haas.ext.obm.mock import MockObm

    with app.app_context():
        # Create a couple projects:
        runway = Project("runway")
        manhattan = Project("manhattan")
        for proj in [runway, manhattan]:
            db.session.add(proj)

        # ...including at least one with nothing in it:
        db.session.add(Project('empty-project'))

        # ...A variety of networks:

        networks = [
            {
                'owner': None,
                'access': [],
                'allocated': True,
                'label': 'stock_int_pub',
            },
            {
                'owner': None,
                'access': [],
                'allocated': False,
                'network_id': 'ext_pub_chan',
                'label': 'stock_ext_pub',
            },
            {
                # For some tests, we want things to initially be attached to a
                # network. This one serves that purpose; using the others would
                # interfere with some of the network_delete tests.
                'owner': None,
                'access': [],
                'allocated': True,
                'label': 'pub_default',
            },
            {
                'owner': runway,
                'access': [runway],
                'allocated': True,
                'label': 'runway_pxe'
            },
            {
                'owner': None,
                'access': [runway],
                'allocated': False,
                'network_id': 'runway_provider_chan',
                'label': 'runway_provider',
            },
            {
                'owner': manhattan,
                'access': [manhattan],
                'allocated': True,
                'label': 'manhattan_pxe'
            },
            {
                'owner': None,
                'access': [manhattan],
                'allocated': False,
                'network_id': 'manhattan_provider_chan',
                'label': 'manhattan_provider',
            },
        ]

        for net in networks:
            if net['allocated']:
                net['network_id'] = \
                    get_network_allocator().get_new_network_id()
            db.session.add(Network(**net))

        # ... Two switches. One of these is just empty, for testing deletion:
        db.session.add(MockSwitch(label='empty-switch',
                                  hostname='empty',
                                  username='******',
                                  password='******',
                                  type=MockSwitch.api_name))

        # ... The other we'll actually attach stuff to for other tests:
        switch = MockSwitch(label="stock_switch_0",
                            hostname='stock',
                            username='******',
                            password='******',
                            type=MockSwitch.api_name)

        # ... Some free ports:
        db.session.add(Port('free_port_0', switch))
        db.session.add(Port('free_port_1', switch))

        # ... Some nodes (with projets):
        nodes = [
            {'label': 'runway_node_0', 'project': runway},
            {'label': 'runway_node_1', 'project': runway},
            {'label': 'manhattan_node_0', 'project': manhattan},
            {'label': 'manhattan_node_1', 'project': manhattan},
            {'label': 'free_node_0', 'project': None},
            {'label': 'free_node_1', 'project': None},
        ]
        for node_dict in nodes:
            obm = MockObm(type=MockObm.api_name,
                          host=node_dict['label'],
                          user='******',
                          password='******')
            node = Node(label=node_dict['label'], obm=obm)
            node.project = node_dict['project']
            db.session.add(Nic(node, label='boot-nic', mac_addr='Unknown'))

            # give it a nic that's attached to a port:
            port_nic = Nic(node, label='nic-with-port', mac_addr='Unknown')
            port = Port(node_dict['label'] + '_port', switch)
            port.nic = port_nic

        # ... Some headnodes:
        headnodes = [
            {'label': 'runway_headnode_on',
             'project': runway,
             'on': True},
            {'label': 'runway_headnode_off',
             'project': runway,
             'on': False},
            {'label': 'runway_manhattan_on',
             'project': manhattan,
             'on': True},
            {'label': 'runway_manhattan_off',
             'project': manhattan,
             'on': False},
        ]
        for hn_dict in headnodes:
            headnode = Headnode(hn_dict['project'],
                                hn_dict['label'],
                                'base-headnode')
            headnode.dirty = not hn_dict['on']
            hnic = Hnic(headnode, 'pxe')
            db.session.add(hnic)

            # Connect them to a network, so we can test detaching.
            hnic = Hnic(headnode, 'public')
            hnic.network = Network.query \
                .filter_by(label='pub_default').one()

        # ... and at least one node with no nics (useful for testing delete):
        obm = MockObm(type=MockObm.api_name,
                      host='hostname',
                      user='******',
                      password='******')
        db.session.add(Node(label='no_nic_node', obm=obm))

        db.session.commit()