Example #1
0
 def del_dynamic_range(self, session, logger, startip, endip):
     dbnet_env = NetworkEnvironment.get_unique_or_default(session)
     startnet = get_net_id_from_ip(session, startip, dbnet_env)
     endnet = get_net_id_from_ip(session, endip, dbnet_env)
     if startnet != endnet:
         raise ArgumentError("IP addresses %s (%s) and %s (%s) must be "
                             "on the same subnet." %
                             (startip, startnet.ip, endip, endnet.ip))
     q = session.query(ARecord)
     q = q.filter_by(network=startnet)
     q = q.filter(ARecord.ip >= startip)
     q = q.filter(ARecord.ip <= endip)
     q = q.order_by(ARecord.ip)
     q = q.options(joinedload('fqdn'), joinedload('fqdn.aliases'),
                   joinedload('fqdn.srv_records'),
                   joinedload('reverse_ptr'))
     existing = q.all()
     if not existing:
         raise ArgumentError("Nothing found in range.")
     if existing[0].ip != startip:
         raise ArgumentError("No system found with IP address %s." %
                             startip)
     if existing[-1].ip != endip:
         raise ArgumentError("No system found with IP address %s." % endip)
     invalid = [s for s in existing if s.dns_record_type != 'dynamic_stub']
     if invalid:
         raise ArgumentError("The range contains non-dynamic systems:\n" +
                             "\n".join([format(i, "a") for i in invalid]))
     self.del_dynamic_stubs(session, logger, existing)
Example #2
0
    def render(self, session, logger, service, **arguments):
        dbservice = Service.get_unique(session, service, compel=True)

        if dbservice.archetypes:
            msg = ", ".join(
                [archetype.name for archetype in dbservice.archetypes])
            raise ArgumentError(
                "Service %s is still required by the following "
                "archetypes: %s." % (dbservice.name, msg))
        if dbservice.personalities:
            msg = ", ".join([
                "%s (%s)" % (personality.name, personality.archetype.name)
                for personality in dbservice.personalities
            ])
            raise ArgumentError(
                "Service %s is still required by the following "
                "personalities: %s." % (dbservice.name, msg))
        if dbservice.instances:
            raise ArgumentError("Service %s still has instances defined and "
                                "cannot be deleted." % dbservice.name)

        session.delete(dbservice)
        session.flush()

        plenary_info = PlenaryService(dbservice, logger=logger)
        plenary_info.remove()

        return
Example #3
0
    def render(self, session, logger, interface, switch, mac, type, comments,
               **arguments):
        if type and type not in self.valid_interface_types:
            raise ArgumentError("Interface type %s is not allowed for "
                                "switches." % type)

        if not type:
            if interface.lower().startswith("lo"):
                type = "loopback"
            else:
                type = "oa"

        for arg in self.invalid_parameters:
            if arguments.get(arg) is not None:
                raise ArgumentError("Cannot use argument --%s when adding an "
                                    "interface to a switch." % arg)

        dbswitch = Switch.get_unique(session, switch, compel=True)
        oldinfo = DSDBRunner.snapshot_hw(dbswitch)

        dbinterface = get_or_create_interface(session, dbswitch,
                                              name=interface, mac=mac,
                                              interface_type=type,
                                              comments=comments, preclude=True)

        session.flush()

        dsdb_runner = DSDBRunner(logger=logger)
        dsdb_runner.update_host(dbswitch, oldinfo)
        dsdb_runner.commit_or_rollback("Could not update switch in DSDB")

        return
Example #4
0
    def render(self, session, logger, dbuser, sandbox, **arguments):
        sandbox = self.force_my_sandbox(session, logger, dbuser, sandbox)
        dbsandbox = Sandbox.get_unique(session, sandbox, compel=True)

        if not dbuser:
            raise AuthorizationException("Cannot get a sandbox without"
                                         " an authenticated connection.")

        userdir = os.path.join(self.config.get("broker", "templatesdir"),
                               dbuser.name)
        sandboxdir = os.path.join(userdir, dbsandbox.name)
        if os.path.exists(sandboxdir):
            raise ArgumentError("Directory '%s' already exists.  Use git "
                                "fetch within the directory to update it." %
                                sandboxdir)

        if not os.path.exists(userdir):
            try:
                logger.client_info("creating %s" % userdir)
                os.makedirs(userdir, mode=0775)
            except OSError, e:
                raise ArgumentError("failed to mkdir %s: %s" % (userdir, e))

            args = [self.config.get("broker", "mean")]
            args.append("chown")
            args.append("-owner")
            args.append("%s" % dbuser.name)
            args.append("-path")
            args.append("%s" % userdir)
            try:
                run_command(args, logger=logger)
            except ProcessException, e:
                remove_dir(userdir)
                raise e
Example #5
0
    def render(self, session, name, type, **arguments):
        dblocation = Location.get_unique(session,
                                         name=name,
                                         location_type=type,
                                         compel=True)

        q = session.query(Network).filter_by(location=dblocation)
        if q.count():
            raise ArgumentError("Could not delete {0:l}, networks were found "
                                "using this location.".format(dblocation))

        q = session.query(NetworkEnvironment).filter_by(location=dblocation)
        if q.count():
            raise ArgumentError(
                "Could not delete {0:l}, network environments "
                "were found using this location.".format(dblocation))

        q = session.query(Cluster).filter_by(location_constraint=dblocation)
        if q.count():
            raise ArgumentError("Could not delete {0:l}, clusters were found "
                                "using this location.".format(dblocation))

        q = session.query(HardwareEntity).filter_by(location=dblocation)
        if q.count():
            raise ArgumentError(
                "Could not delete {0:l}, hardware objects were "
                "found using this location.".format(dblocation))

        session.delete(dblocation)
        return
Example #6
0
    def render(self, session, dbuser, ip, network_environment, **arguments):
        dbnet_env = NetworkEnvironment.get_unique_or_default(
            session, network_environment)
        self.az.check_network_environment(dbuser, dbnet_env)

        dbnetwork = Network.get_unique(session,
                                       network_environment=dbnet_env,
                                       ip=ip,
                                       compel=True)

        # Delete the routers so they don't trigger the checks below
        for dbrouter in dbnetwork.routers:
            map(delete_dns_record, dbrouter.dns_records)
        dbnetwork.routers = []
        session.flush()

        if dbnetwork.dns_records:
            raise ArgumentError("{0} is still in use by DNS entries and "
                                "cannot be deleted.".format(dbnetwork))
        if dbnetwork.assignments:
            raise ArgumentError("{0} is still in use by hosts and "
                                "cannot be deleted.".format(dbnetwork))

        session.delete(dbnetwork)
        session.flush()
        return
    def render(self, session, feature, type, path, **kwargs):
        dbfeature = Feature.get_unique(session,
                                       name=feature,
                                       feature_type=type,
                                       compel=True)
        if not dbfeature.paramdef_holder:
            raise ArgumentError(
                "No parameter definitions found for {0:l}.".format(dbfeature))

        db_paramdef = ParamDefinition.get_unique(
            session, path=path, holder=dbfeature.paramdef_holder, compel=True)

        ## validate if this path is being used
        holder = search_path_in_personas(session, path,
                                         dbfeature.paramdef_holder)
        if holder:
            raise ArgumentError(
                "Parameter with path {0} used by following and cannot be deleted : "
                .format(path) + ", ".join([
                    "{0.holder_object:l}".format(h) for h in holder.iterkeys()
                ]))

        session.delete(db_paramdef)
        session.flush()

        return
Example #8
0
    def render(self, session, logger, machine, disk, controller, size, all,
               dbuser, **arguments):

        # Handle deprecated arguments
        if arguments.get("type", None):
            self.deprecated_option("type",
                                   "Please use --controller instead.",
                                   logger=logger,
                                   **arguments)
            controller = arguments["type"]
        if arguments.get("capacity", None):
            self.deprecated_option("capacity",
                                   "Please use --size instead.",
                                   logger=logger,
                                   **arguments)
            size = arguments["capacity"]

        dbmachine = Machine.get_unique(session, machine, compel=True)
        q = session.query(Disk).filter_by(machine=dbmachine)
        if disk:
            q = q.filter_by(device_name=disk)
        if controller:
            if controller not in controller_types:
                raise ArgumentError("%s is not a valid controller type, use "
                                    "one of: %s." %
                                    (controller, ", ".join(controller_types)))
            q = q.filter_by(controller_type=controller)
        if size is not None:
            q = q.filter_by(capacity=size)
        results = q.all()

        if len(results) == 0:
            raise NotFoundException("No disks found.")
        elif len(results) > 1 and not all:
            raise ArgumentError("More than one matching disks found.  "
                                "Use --all to delete them all.")
        for result in results:
            session.delete(result)

        session.flush()
        session.expire(dbmachine, ['disks'])

        plenary_machine = Plenary.get_plenary(dbmachine, logger=logger)
        key = plenary_machine.get_write_key()
        dbcontainer = dbmachine.vm_container
        if dbcontainer:
            plenary_container = Plenary.get_plenary(dbcontainer, logger=logger)
            key = CompileKey.merge([key, plenary_container.get_write_key()])
        try:
            lock_queue.acquire(key)
            if dbcontainer:
                plenary_container.write(locked=True)
            plenary_machine.write(locked=True)
        except:
            plenary_machine.restore_stash()
            if dbcontainer:
                plenary_container.restore_stash()
            raise
        finally:
            lock_queue.release(key)
Example #9
0
    def adjust_slot(self, session, logger,
                    dbmachine, dbchassis, slot, multislot):
        for dbslot in dbmachine.chassis_slot:
            # This update is a noop, ignore.
            # Technically, this could be a request to trim the list down
            # to just this one slot - in that case --clearchassis will be
            # required.
            if dbslot.chassis == dbchassis and dbslot.slot_number == slot:
                return
        if len(dbmachine.chassis_slot) > 1 and not multislot:
            raise ArgumentError("Use --multislot to support a machine in more "
                                "than one slot, or --clearchassis to remove "
                                "current chassis slot information.")
        if not multislot:
            slots = ", ".join([str(dbslot.slot_number) for dbslot in
                               dbmachine.chassis_slot])
            logger.info("Clearing {0:l} out of {1:l} slot(s) "
                        "{2}".format(dbmachine, dbchassis, slots))
            del dbmachine.chassis_slot[:]
        q = session.query(ChassisSlot)
        q = q.filter_by(chassis=dbchassis, slot_number=slot)
        dbslot = q.first()
        if dbslot:
            if dbslot.machine:
                raise ArgumentError("{0} slot {1} already has machine "
                                    "{2}.".format(dbchassis, slot,
                                                  dbslot.machine.label))
        else:
            dbslot = ChassisSlot(chassis=dbchassis, slot_number=slot)
        dbmachine.chassis_slot.append(dbslot)

        return
Example #10
0
def validate_parameter(session, path, value, param_holder, featurelink=None):
    """
        Validates parameter before updating in db.
        - checks if matching parameter definition exists
        - if value is not specified on input if a default value
          has been defined on the definition
        - if rebuild_required validate do validation on host status
    """

    match = get_paramdef_for_parameter(session, path, param_holder,
                                       featurelink)
    if not match:
        raise ArgumentError(
            "Parameter %s does not match any parameter definitions" % path)

    retval = None

    ## check if default specified on parameter definition
    if not value:
        if match.default:
            value = match.default
        else:
            raise ArgumentError(
                "Parameter %s does not have any value defined." % path)

    retval = validate_value(path, match.value_type, value)

    if match.rebuild_required:
        validate_rebuild_required(session, path, param_holder)

    return retval, match
Example #11
0
    def render(self, session, logger, grn, eon_id, **arguments):
        dbgrn = lookup_grn(session,
                           grn,
                           eon_id,
                           logger=logger,
                           config=self.config,
                           usable_only=False)

        q1 = session.query(Host)
        q1 = q1.filter_by(owner_eon_id=dbgrn.eon_id)
        q2 = session.query(HostGrnMap)
        q2 = q2.filter_by(eon_id=dbgrn.eon_id)
        if q1.first() or q2.first():
            raise ArgumentError("GRN %s is still used by hosts, and "
                                "cannot be deleted." % dbgrn.grn)

        q1 = session.query(Personality)
        q1 = q1.filter_by(owner_eon_id=dbgrn.eon_id)
        q2 = session.query(PersonalityGrnMap)
        q2 = q2.filter_by(eon_id=dbgrn.eon_id)
        if q1.first() or q2.first():
            raise ArgumentError("GRN %s is still used by personalities, "
                                "and cannot be deleted." % dbgrn.grn)

        session.delete(dbgrn)
        session.flush()
        return
Example #12
0
def assign_address(dbinterface, ip, dbnetwork, label=None, resource=None):
    assert isinstance(dbinterface, Interface)

    dns_environment = dbnetwork.network_environment.dns_environment

    if dbinterface.master:
        raise ArgumentError("Slave interfaces cannot hold addresses.")

    for addr in dbinterface.assignments:
        if not label and not addr.label:
            raise ArgumentError("{0} already has an IP "
                                "address.".format(dbinterface))
        if label and addr.label == label:
            raise ArgumentError("{0} already has an alias named "
                                "{1}.".format(dbinterface, label))
        if addr.network.network_environment != dbnetwork.network_environment:
            raise ArgumentError("{0} already has an IP address from "
                                "{1:l}.  Network environments cannot be "
                                "mixed.".format(
                                    dbinterface,
                                    addr.network.network_environment))
        if addr.ip == ip:
            raise ArgumentError("{0} already has IP address {1} "
                                "configured.".format(dbinterface, ip))

    dbinterface.assignments.append(
        AddressAssignment(ip=ip,
                          network=dbnetwork,
                          label=label,
                          service_address=resource,
                          dns_environment=dns_environment))
Example #13
0
    def onEnter(self, dbcluster):
        dbdecommissioned = HostLifecycle.get_unique(object_session(dbcluster),
                                                    "decommissioned",
                                                    compel=True)

        config = Config()
        archetype = dbcluster.personality.archetype
        section = "archetype_" + archetype.name
        opt = "allow_cascaded_deco"

        if dbcluster.hosts and (not config.has_option(section, opt)
                                or not config.getboolean(section, opt)):
            raise ArgumentError("Cannot change state to {0}, as {1}'s "
                                "archetype is {2}.".format(
                                    dbdecommissioned.name, dbcluster,
                                    archetype.name))

        if dbcluster.machines:
            raise ArgumentError("Cannot change state to {0}, as {1} has "
                                "{2} VM(s).".format(dbdecommissioned.name,
                                                    dbcluster,
                                                    len(dbcluster.machines)))

        for dbhost in dbcluster.hosts:
            dbhost.status.transition(dbhost, dbdecommissioned)
Example #14
0
    def render(self, session, logger, interface, chassis, mac, type, comments,
               **arguments):
        if type and type != "oa":
            raise ArgumentError("Only 'oa' is allowed as the interface type "
                                "for chassis.")

        for arg in self.invalid_parameters:
            if arguments.get(arg) is not None:
                raise ArgumentError("Cannot use argument --%s when adding an "
                                    "interface to a chassis." % arg)

        dbchassis = Chassis.get_unique(session, chassis, compel=True)
        oldinfo = DSDBRunner.snapshot_hw(dbchassis)

        dbinterface = get_or_create_interface(session, dbchassis,
                                              name=interface, mac=mac,
                                              interface_type='oa',
                                              comments=comments, preclude=True)

        session.flush()

        dsdb_runner = DSDBRunner(logger=logger)
        dsdb_runner.update_host(dbchassis, oldinfo)
        dsdb_runner.commit_or_rollback("Could not update chassis in DSDB")

        return
Example #15
0
    def render(self, session, logger, model, vendor, **arguments):
        dbvendor = Vendor.get_unique(session, vendor, compel=True)
        dbmodel = Model.get_unique(session,
                                   name=model,
                                   vendor=dbvendor,
                                   compel=True)

        if dbmodel.machine_type == 'nic':
            q = session.query(Interface)
            q = q.filter_by(model=dbmodel)
            if q.first():
                raise ArgumentError("{0} is still in use and cannot be "
                                    "deleted.".format(dbmodel))
            q = session.query(MachineSpecs)
            q = q.filter_by(nic_model=dbmodel)
            if q.first():
                raise ArgumentError(
                    "{0} is still referenced by machine models and "
                    "cannot be deleted.".format(dbmodel))
        else:
            q = session.query(HardwareEntity)
            q = q.filter_by(model=dbmodel)
            if q.first():
                raise ArgumentError("{0} is still in use and cannot be "
                                    "deleted.".format(dbmodel))

        if dbmodel.machine_specs:
            # FIXME: Log some details...
            logger.info("Before deleting model %s %s '%s', "
                        "removing machine specifications." %
                        (dbmodel.machine_type, dbvendor.name, dbmodel.name))
            session.delete(dbmodel.machine_specs)
        session.delete(dbmodel)
        return
Example #16
0
    def render(self, session, dns_environment, **arguments):
        db_dnsenv = DnsEnvironment.get_unique(session, dns_environment,
                                              compel=True)

        if db_dnsenv.is_default:
            raise ArgumentError("{0} is the default DNS environment, "
                                "therefore it cannot be deleted."
                                .format(db_dnsenv))
        q = session.query(Fqdn)
        q = q.filter_by(dns_environment=db_dnsenv)
        if q.first():
            raise ArgumentError("{0} is still in use by DNS records, and "
                                "cannot be deleted.".format(db_dnsenv))

        q = session.query(RouterAddress)
        q = q.filter_by(dns_environment=db_dnsenv)
        if q.first():
            raise ArgumentError("{0} is still in use by routers, and "
                                "cannot be deleted.".format(db_dnsenv))

        q = session.query(AddressAssignment)
        q = q.filter_by(dns_environment=db_dnsenv)
        if q.first():
            raise ArgumentError("{0} is still in use by address assignments, "
                                "and cannot be deleted.".format(db_dnsenv))

        session.delete(db_dnsenv)
        session.flush()

        return
Example #17
0
    def render(self, session, dbuser, ip, netmask, prefixlen,
               network_environment, **arguments):
        if netmask:
            # There must me a faster way, but this is the easy one
            net = IPv4Network("127.0.0.0/%s" % netmask)
            prefixlen = net.prefixlen
        if prefixlen is None or prefixlen < 8 or prefixlen > 31:
            raise ArgumentError("The prefix length must be between 8 and 31.")

        dbnet_env = NetworkEnvironment.get_unique_or_default(
            session, network_environment)
        self.az.check_network_environment(dbuser, dbnet_env)

        dbnetwork = get_net_id_from_ip(session,
                                       ip,
                                       network_environment=dbnet_env)

        if prefixlen >= dbnetwork.cidr:
            raise ArgumentError("The specified --prefixlen must be smaller "
                                "than the current value.")

        # IPv4Network has a supernet() object, but that does not normalize the
        # IP address, i.e. IPv4Network('1.2.3.0/24').supernet() will return
        # IPv4Network('1.2.3.0/23'). Do the normalization manually.
        supernet = dbnetwork.network.supernet(new_prefix=prefixlen)
        supernet = IPv4Network("%s/%d" %
                               (supernet.network, supernet.prefixlen))

        q = session.query(Network)
        q = q.filter_by(network_environment=dbnet_env)
        q = q.filter(
            and_(Network.ip >= supernet.ip, Network.ip < supernet.broadcast))
        q = q.order_by(Network.ip)
        dbnets = q.all()

        if dbnets[0].ip == supernet.ip:
            dbsuper = dbnets.pop(0)
            dbsuper.cidr = prefixlen
        else:
            # Create a new network, copying the parameters from the one
            # specified on the command line
            dbsuper = Network(name=dbnetwork.name,
                              network=supernet,
                              network_environment=dbnet_env,
                              location=dbnetwork.location,
                              side=dbnetwork.side,
                              comments=dbnetwork.comments)
            session.add(dbsuper)

        for oldnet in dbnets:
            # Delete routers of the old subnets
            for dbrouter in oldnet.routers:
                map(delete_dns_record, dbrouter.dns_records)
            oldnet.routers = []

            fix_foreign_links(session, oldnet, dbsuper)
            session.delete(oldnet)

        session.flush()
Example #18
0
    def render(self, session, logger, branch, sandbox, bundle, sync, rebase,
               **arguments):
        # Most of the logic here is duplicated in deploy
        if branch:
            sandbox = branch
        dbsandbox = Sandbox.get_unique(session, sandbox, compel=True)

        (handle, filename) = mkstemp()
        contents = b64decode(bundle)
        write_file(filename, contents, logger=logger)

        if sync and not dbsandbox.is_sync_valid and dbsandbox.trackers:
            # FIXME: Maybe raise an ArgumentError and request that the
            # command run with --nosync?  Maybe provide a --validate flag?
            # For now, we just auto-flip anyway (below) making the point moot.
            pass
        if not dbsandbox.is_sync_valid:
            dbsandbox.is_sync_valid = True

        if rebase and dbsandbox.trackers:
            raise ArgumentError(
                "{0} has trackers, rebasing is not allowed.".format(dbsandbox))

        kingdir = self.config.get("broker", "kingdir")
        rundir = self.config.get("broker", "rundir")

        tempdir = mkdtemp(prefix="publish_",
                          suffix="_%s" % dbsandbox.name,
                          dir=rundir)
        try:
            run_git([
                "clone", "--shared", "--branch", dbsandbox.name, kingdir,
                dbsandbox.name
            ],
                    path=tempdir,
                    logger=logger)
            temprepo = os.path.join(tempdir, dbsandbox.name)
            run_git(["bundle", "verify", filename],
                    path=temprepo,
                    logger=logger)
            ref = "HEAD:%s" % (dbsandbox.name)
            command = ["pull", filename, ref]
            if rebase:
                command.append("--force")
            run_git(command,
                    path=temprepo,
                    logger=logger,
                    loglevel=CLIENT_INFO)
            # FIXME: Run tests before pushing back to template-king
            if rebase:
                target_ref = "+" + dbsandbox.name
            else:
                target_ref = dbsandbox.name
            run_git(["push", "origin", target_ref],
                    path=temprepo,
                    logger=logger)
        except ProcessException, e:
            raise ArgumentError("\n%s%s" % (e.out, e.err))
Example #19
0
def expand_compiler(config, compiler_version):
    if not VERSION_RE.match(compiler_version):
        raise ArgumentError("Invalid characters in compiler version")
    compiler = config.get("panc", "pan_compiler", raw=True) % {
        'version': compiler_version
    }
    if not os.path.exists(compiler):
        raise ArgumentError("Compiler not found at '%s'" % compiler)
    return compiler
Example #20
0
 def render(self, session, vendor, **arguments):
     dbvendor = Vendor.get_unique(session, vendor, compel=True)
     if session.query(Model).filter_by(vendor=dbvendor).first():
         raise ArgumentError("Vendor %s is still in use by a model." %
                             dbvendor.name)
     if session.query(Cpu).filter_by(vendor=dbvendor).first():
         raise ArgumentError("Vendor %s is still in use by a CPU." %
                             dbvendor.name)
     session.delete(dbvendor)
     return
Example #21
0
    def __init__(self, service, protocol, dns_domain, dns_environment,
                 priority, weight, port, target, **kwargs):
        if not isinstance(target, Fqdn):  # pragma: no cover
            raise TypeError("The target of an SRV record must be an Fqdn.")
        session = object_session(target)
        if not session:  # pragma: no cover
            raise AquilonError("The target name must already be part of "
                               "the session.")
        # SRV records are special, as the FQDN is managed internally
        if "fqdn" in kwargs:  # pragma: no cover
            raise AquilonError("SRV records do not accept an FQDN argument.")

        self.validate_ushort('priority', priority)
        self.validate_ushort('weight', weight)
        self.validate_ushort('port', port)

        # RFC 2782:
        # - there must be one or more address records for the target
        # - the target must not be an alias
        found_address = False
        for rr in target.dns_records:
            if isinstance(rr, ARecord):
                found_address = True
            elif isinstance(rr, Alias):
                raise ArgumentError("The target of an SRV record must not be "
                                    "an alias.")
        if not found_address:
            raise ArgumentError("The target of an SRV record must resolve to "
                                "one or more addresses.")

        if protocol not in PROTOCOLS:
            raise ArgumentError("Unknown protocol %s." % protocol)
        name = "_%s._%s" % (service.strip().lower(), protocol.strip().lower())

        # Disable autoflush because self is not ready to be pushed to the DB yet
        with session.no_autoflush:
            fqdn = Fqdn.get_or_create(session,
                                      name=name,
                                      dns_domain=dns_domain,
                                      dns_environment=dns_environment,
                                      ignore_name_check=True)

            # Do not allow two SRV records pointing at the same target
            for rr in fqdn.dns_records:
                if isinstance(rr, SrvRecord) and rr.target == target and \
                   rr.protocol == protocol and rr.service == service:
                    raise ArgumentError("{0} already exists.".format(rr))

        super(SrvRecord, self).__init__(fqdn=fqdn,
                                        priority=priority,
                                        weight=weight,
                                        port=port,
                                        target=target,
                                        **kwargs)
Example #22
0
def update_primary_ip(session, dbhw_ent, ip):
    if not dbhw_ent.primary_name:
        raise ArgumentError(
            "{0} does not have a primary name.".format(dbhw_ent))

    dbnetwork = get_net_id_from_ip(session, ip)
    check_ip_restrictions(dbnetwork, ip)

    # The primary address must be unique
    q = session.query(AddressAssignment)
    q = q.filter_by(network=dbnetwork)
    q = q.filter_by(ip=ip)
    addr = q.first()
    if addr:
        raise ArgumentError(
            "IP address {0} is already in use by {1:l}.".format(
                ip, addr.interface))

    # Convert ReservedName to ARecord if needed
    if isinstance(dbhw_ent.primary_name, ReservedName):
        convert_reserved_to_arecord(session, dbhw_ent.primary_name, dbnetwork,
                                    ip)

        # When converting a ReservedName to an ARecord, we have to bind the
        # primary address to an interface. Try to pick one.
        dbinterface = first_of(dbhw_ent.interfaces, lambda x: x.bootable)
        if not dbinterface:
            dbinterface = first_of(dbhw_ent.interfaces,
                                   lambda x: x.interface_type != "management")

        if not dbinterface:  # pragma: no cover
            raise AquilonError("Cannot update the primary IP address of {0:l} "
                               "because it does not have any interfaces "
                               "defined.".format(dbhw_ent))

        assign_address(dbinterface, ip, dbnetwork)
    else:
        dns_rec = dbhw_ent.primary_name

        q = session.query(AddressAssignment)
        q = q.filter_by(network=dns_rec.network)
        q = q.filter_by(ip=dns_rec.ip)
        q = q.join(Interface)
        q = q.filter_by(hardware_entity=dbhw_ent)
        # In case of Zebra, the address may be assigned to multiple interfaces
        addrs = q.all()

        dns_rec.ip = ip
        dns_rec.network = dbnetwork

        for addr in addrs:
            addr.ip = ip
            addr.network = dbnetwork
Example #23
0
    def render(self, session, logger, hostname, cluster, personality,
               **arguments):
        dbcluster = Cluster.get_unique(session, cluster, compel=True)
        dbhost = hostname_to_host(session, hostname)
        if not dbhost.cluster:
            raise ArgumentError(
                "{0} is not bound to a cluster.".format(dbhost))
        if dbhost.cluster != dbcluster:
            raise ArgumentError("{0} is bound to {1:l}, not {2:l}.".format(
                dbhost, dbhost.cluster, dbcluster))

        if personality:
            dbpersonality = Personality.get_unique(session,
                                                   name=personality,
                                                   archetype=dbhost.archetype,
                                                   compel=True)
            if dbpersonality.cluster_required:
                raise ArgumentError("Cannot switch host to personality %s "
                                    "because that personality requires a "
                                    "cluster" % personality)
            dbhost.personality = dbpersonality
        elif dbhost.personality.cluster_required:
            raise ArgumentError("Host personality %s requires a cluster, "
                                "use --personality to change personality "
                                "when leaving the cluster." %
                                dbhost.personality.name)

        dbcluster.hosts.remove(dbhost)
        remove_service_addresses(dbcluster, dbhost)
        dbcluster.validate()

        session.flush()
        session.expire(dbhost, ['_cluster'])

        # Will need to write a cluster plenary and either write or
        # remove a host plenary.  Grab the domain key since the two
        # must be in the same domain.
        host_plenary = Plenary.get_plenary(dbhost, logger=logger)
        cluster_plenary = Plenary.get_plenary(dbcluster, logger=logger)
        key = CompileKey(domain=dbcluster.branch.name, logger=logger)
        try:
            lock_queue.acquire(key)
            cluster_plenary.write(locked=True)
            try:
                host_plenary.write(locked=True)
            except IncompleteError:
                host_plenary.cleanup(domain=dbhost.branch.name, locked=True)
        except:
            cluster_plenary.restore_stash()
            host_plenary.restore_stash()
            raise
        finally:
            lock_queue.release(key)
Example #24
0
    def render(self, session, dbuser, fqdn, building, ip, network_environment,
               comments, **arguments):
        dbnet_env = NetworkEnvironment.get_unique_or_default(
            session, network_environment)
        self.az.check_network_environment(dbuser, dbnet_env)

        if building:
            dbbuilding = Building.get_unique(session, building, compel=True)
        else:
            dbbuilding = None

        (short, dbdns_domain) = parse_fqdn(session, fqdn)
        dbfqdn = Fqdn.get_or_create(session,
                                    name=short,
                                    dns_domain=dbdns_domain,
                                    dns_environment=dbnet_env.dns_environment)
        if ip:
            dbnetwork = get_net_id_from_ip(session, ip, dbnet_env)
            dbdns_rec = ARecord.get_or_create(session,
                                              fqdn=dbfqdn,
                                              ip=ip,
                                              network=dbnetwork)
        else:
            dbdns_rec = ARecord.get_unique(session, dbfqdn, compel=True)
            ip = dbdns_rec.ip
            dbnetwork = dbdns_rec.network

        assert ip in dbnetwork.network, "IP %s is outside network %s" % (
            ip, dbnetwork.ip)

        if ip in dbnetwork.router_ips:
            raise ArgumentError(
                "IP address {0} is already present as a router "
                "for {1:l}.".format(ip, dbnetwork))

        # Policy checks are valid only for internal networks
        if dbnetwork.is_internal:
            if ip >= dbnetwork.first_usable_host or \
               int(ip) - int(dbnetwork.ip) in dbnetwork.reserved_offsets:
                raise ArgumentError(
                    "IP address {0} is not a valid router address "
                    "on {1:l}.".format(ip, dbnetwork))

        dbnetwork.routers.append(
            RouterAddress(ip=ip,
                          location=dbbuilding,
                          dns_environment=dbdns_rec.fqdn.dns_environment,
                          comments=comments))
        session.flush()

        # TODO: update the templates of Zebra hosts on the network

        return
Example #25
0
def update_cluster_location(session, logger, dbcluster, fix_location,
                            plenaries, remove_plenaries, **arguments):
    location_updated = False
    dblocation = get_location(session, **arguments)
    if fix_location:
        dblocation = dbcluster.minimum_location
        if not dblocation:
            raise ArgumentError("Cannot infer the cluster location from "
                                "the host locations.")
    if dblocation:
        errors = []
        if not dblocation.campus:
            errors.append("{0} is not within a campus.".format(dblocation))

        if dbcluster.cluster_type != 'meta':
            for host in dbcluster.hosts:
                if host.machine.location != dblocation and \
                   dblocation not in host.machine.location.parents:
                    errors.append("{0} has location {1}.".format(
                        host, host.machine.location))
        else:
            for cluster in dbcluster.members:
                if cluster.location_constraint != dblocation and \
                   dblocation not in cluster.location_constraint.parents:
                    errors.append("{0} has location {1}.".format(
                        cluster, cluster.location_constraint))

        if errors:
            raise ArgumentError("Cannot set {0} location constraint to "
                                "{1}:\n{2}".format(dbcluster, dblocation,
                                                   "\n".join(errors)))

        if dbcluster.location_constraint != dblocation:
            if machine_plenary_will_move(old=dbcluster.location_constraint,
                                         new=dblocation):
                for dbmachine in dbcluster.machines:
                    # This plenary will have a path to the old location.
                    plenary = Plenary.get_plenary(dbmachine, logger=logger)
                    remove_plenaries.append(plenary)
                    dbmachine.location = dblocation
                    session.add(dbmachine)
                    # This plenary will have a path to the new location.
                    plenaries.append(Plenary.get_plenary(dbmachine))
                    # Update the path to the machine plenary in the
                    # container resource
                    plenaries.append(
                        Plenary.get_plenary(dbmachine.vm_container))
            dbcluster.location_constraint = dblocation
            location_updated = True

    return location_updated
Example #26
0
def verify_port_group(dbmachine, port_group):
    """Validate that the port_group can be used on an interface.

    If the machine is virtual, check that the corresponding VLAN has
    been observed on the cluster's switch.

    If the machine is physical but is part of an ESX cluster, also
    check that the VLAN has been observed.

    Otherwise just accept the label.

    As a convenience, return None (unset the port_group) if an empty
    string is passed in.

    """
    if not port_group:
        return None
    session = object_session(dbmachine)
    dbvi = VlanInfo.get_unique(session, port_group=port_group, compel=True)
    if dbmachine.model.machine_type == "virtual_machine":
        dbswitch = dbmachine.cluster.switch
        if not dbswitch:
            raise ArgumentError("Cannot verify port group availability: no "
                                "switch record for {0}.".format(
                                    dbmachine.cluster))
        q = session.query(ObservedVlan)
        q = q.filter_by(vlan_id=dbvi.vlan_id)
        q = q.filter_by(switch=dbswitch)
        try:
            dbobserved_vlan = q.one()
        except NoResultFound:
            raise ArgumentError("Cannot verify port group availability: "
                                "no record for VLAN {0} on "
                                "{1:l}.".format(dbvi.vlan_id, dbswitch))
        except MultipleResultsFound:  # pragma: no cover
            raise InternalError("Too many subnets found for VLAN {0} "
                                "on {1:l}.".format(dbvi.vlan_id, dbswitch))
        if dbobserved_vlan.network.is_at_guest_capacity:
            raise ArgumentError("Port group {0} is full for "
                                "{1:l}.".format(dbvi.port_group,
                                                dbobserved_vlan.switch))
    elif dbmachine.host and dbmachine.host.cluster and \
         dbmachine.host.cluster.switch:
        dbswitch = dbmachine.host.cluster.switch
        q = session.query(ObservedVlan)
        q = q.filter_by(vlan_id=dbvi.vlan_id, switch=dbswitch)
        if not q.count():
            raise ArgumentError("VLAN {0} not found for "
                                "{1:l}.".format(dbvi.vlan_id, dbswitch))
    return dbvi.port_group
Example #27
0
    def render(self, session, auxiliary, **kwargs):
        dbdns_rec = ARecord.get_unique(session, fqdn=auxiliary, compel=True)
        if not dbdns_rec.assignments:
            raise ArgumentError("Address {0:a} is not assigned to any "
                                "interfaces.".format(dbdns_rec))
        hws = []
        for addr in dbdns_rec.assignments:
            iface = addr.interface
            if iface.interface_type != 'public':
                raise ArgumentError(
                    "{0:a} is not an auxiliary.".format(dbdns_rec))
            hws.append(iface.hardware_entity)

        return hws
Example #28
0
    def render(self, session, logger, domain, ref, lastsync, **arguments):
        dbdomain = Domain.get_unique(session, domain, compel=True)
        if not dbdomain.tracked_branch:
            # Could check dbdomain.trackers and rollback all of them...
            raise ArgumentError("rollback requires a tracking domain")

        if lastsync:
            if not dbdomain.rollback_commit:
                raise ArgumentError("domain %s does not have a rollback "
                                    "commit saved, please specify one "
                                    "explicitly." % dbdomain.name)
            ref = dbdomain.rollback_commit

        if not ref:
            raise ArgumentError("Commit reference to rollback to required.")

        kingdir = self.config.get("broker", "kingdir")
        domaindir = os.path.join(self.config.get("broker", "domainsdir"),
                                 dbdomain.name)
        out = run_git(["branch", "--contains", ref],
                      logger=logger,
                      path=kingdir)
        if not re.search(r'\b%s\b' % dbdomain.tracked_branch.name, out):
            # There's no real technical reason why this needs to be
            # true.  It just seems like a good sanity check.
            raise ArgumentError("Cannot roll back to commit: "
                                "branch %s does not contain %s" %
                                (dbdomain.tracked_branch.name, ref))

        dbdomain.tracked_branch.is_sync_valid = False
        session.add(dbdomain.tracked_branch)
        dbdomain.rollback_commit = None
        session.add(dbdomain)

        key = CompileKey(domain=dbdomain.name, logger=logger)
        try:
            lock_queue.acquire(key)
            run_git(["push", ".", "+%s:%s" % (ref, dbdomain.name)],
                    path=kingdir,
                    logger=logger)
            # Duplicated this logic from aquilon.worker.processes.sync_domain()
            run_git(["fetch"], path=domaindir, logger=logger)
            run_git(["reset", "--hard",
                     "origin/%s" % dbdomain.name],
                    path=domaindir,
                    logger=logger)
        except ProcessException, e:
            raise ArgumentError(
                "Problem encountered updating templates for "
                "domain %s: %s", dbdomain.name, e)
Example #29
0
    def generate_mac(self, session, dbmachine):
        """ Generate a mac address for virtual hardware.

        Algorithm:

        * Query for first mac address in aqdb starting with vendor prefix,
          order by mac descending.
        * If no address, or address less than prefix start, use prefix start.
        * If the found address is not suffix end, increment by one and use it.
        * If the address is suffix end, requery for the full list and scan
          through for holes. Use the first hole.
        * If no holes, error. [In this case, we're still not completely dead
          in the water - the mac address would just need to be given manually.]

        """
        if dbmachine.model.machine_type != "virtual_machine":
            raise ArgumentError("Can only automatically generate MAC "
                                "addresses for virtual hardware.")
        if not dbmachine.cluster or dbmachine.cluster.cluster_type != 'esx':
            raise UnimplementedError("MAC address auto-generation has only "
                                     "been enabled for ESX Clusters.")
        # FIXME: These values should probably be configurable.
        mac_prefix_esx = "00:50:56"
        mac_start_esx = mac_prefix_esx + ":01:20:00"
        mac_end_esx = mac_prefix_esx + ":3f:ff:ff"
        mac_start = MACAddress(mac_start_esx)
        mac_end = MACAddress(mac_end_esx)
        q = session.query(Interface.mac)
        q = q.filter(Interface.mac.between(str(mac_start), str(mac_end)))
        # This query (with a different order_by) is used below.
        mac = q.order_by(desc(Interface.mac)).first()
        if not mac:
            return str(mac_start)
        highest_mac = MACAddress(mac[0])
        if highest_mac < mac_start:
            return str(mac_start)
        if highest_mac < mac_end:
            return str(highest_mac.next())
        potential_hole = mac_start
        for mac in q.order_by(asc(Interface.mac)).all():
            current_mac = MACAddress(mac[0])
            if current_mac < mac_start:
                continue
            if potential_hole < current_mac:
                return str(potential_hole)
            potential_hole = current_mac.next()
        raise ArgumentError("All MAC addresses between %s and %s inclusive "
                            "are currently in use." % (mac_start, mac_end))
Example #30
0
 def validate_type(cls, value_type):
     """ Utility function for validating the value type """
     if value_type in _PATH_TYPES:
         return
     valid_types = ", ".join(sorted(_PATH_TYPES))
     raise ArgumentError("Unknown value type '%s'.  The valid types are: "
                         "%s." % (value_type, valid_types))