Beispiel #1
0
def main():
    """
    Main execution routine

    :return: None
    """
    creds = Credentials('apic')
    creds.add_argument('--tenant', help='The name of Tenant')
    creds.add_argument('--app', help='The name of ApplicationProfile')
    creds.add_argument('--bd', help='The name of BridgeDomain')
    creds.add_argument('--epg', help='The name of EPG')
    creds.add_argument('--json',
                       const='false',
                       nargs='?',
                       help='Json output only')

    args = creds.get()
    session = Session(args.url, args.login, args.password)
    session.login()

    tenant = Tenant(args.tenant)
    app = AppProfile(args.app, tenant)
    bd = BridgeDomain(args.bd, tenant)
    epg = EPG(args.epg, app)
    epg.add_bd(bd)

    if args.json:
        print(tenant.get_json())
    else:
        resp = session.push_to_apic(tenant.get_url(), tenant.get_json())

        if not resp.ok:
            print('%% Error: Could not push configuration to APIC')
            print(resp.text)
Beispiel #2
0
def main():
    """
    Main execution routine
    """
    creds = Credentials('apic')
    args = creds.get()
    session = Session(args.url, args.login, args.password)
    session.login()

    tenant = Tenant('ATX16_l3Out')
    context = Context('vrf', tenant)
    outside_l3 = OutsideL3('out-1', tenant)
    outside_l3.add_context(context)
    phyif = Interface('eth', '1', '104', '1', '41')
    phyif.speed = '1G'
    l2if = L2Interface('eth 1/104/1/41', 'vlan', '1330')
    l2if.attach(phyif)
    l3if = L3Interface('l3if')
    #l3if.set_l3if_type('l3-port')
    l3if.set_l3if_type('sub-interface')
    l3if.set_mtu('1500')
    l3if.set_addr('1.1.1.2/30')
    l3if.add_context(context)
    l3if.attach(l2if)
    rtr = OSPFRouter('rtr-1')
    rtr.set_router_id('23.23.23.23')
    rtr.set_node_id('101')
    ifpol = OSPFInterfacePolicy('myospf-pol', tenant)
    ifpol.set_nw_type('p2p')
    ospfif = OSPFInterface('ospfif-1', router=rtr, area_id='1')
    ospfif.set_area_type('nssa')
    ospfif.auth_key = 'password'
    ospfif.int_policy_name = ifpol.name
    ospfif.auth_keyid = '1'
    ospfif.auth_type = 'simple'
    tenant.attach(ospfif)
    ospfif.networks.append('55.5.5.0/24')
    ospfif.attach(l3if)
    contract1 = Contract('contract-1')
    outside_epg = OutsideEPG('outepg', outside_l3)
    outside_epg.provide(contract1)
    contract2 = Contract('contract-2')
    outside_epg.consume(contract2)
    outside_l3.attach(ospfif)

    print(tenant.get_json())
    resp = session.push_to_apic(tenant.get_url(), tenant.get_json())

    if not resp.ok:
        print('%% Error: Could not push configuration to APIC')
        print(resp.text)
def main():
    """
    Main execution routine
    """
    creds = Credentials('apic')
    args = creds.get()
    session = Session(args.url, args.login, args.password)
    session.login()

    tenant = Tenant('Cisco-Demo')
    context = Context('ctx1', tenant)
    outside_l3 = OutsideL3('out-1', tenant)
    outside_l3.add_context(context)
    phyif = Interface('eth', '1', '101', '1', '46')
    phyif.speed = '1G'
    l2if = L2Interface('eth 1/101/1/46', 'vlan', '1')
    l2if.attach(phyif)
    l3if = L3Interface('l3if')
    l3if.set_l3if_type('l3-port')
    l3if.set_mtu('1500')
    l3if.set_addr('1.1.1.2/30')
    l3if.add_context(context)
    l3if.attach(l2if)
    rtr = OSPFRouter('rtr-1')
    rtr.set_router_id('23.23.23.23')
    rtr.set_node_id('101')
    ifpol = OSPFInterfacePolicy('myospf-pol', tenant)
    ifpol.set_nw_type('p2p')
    ospfif = OSPFInterface('ospfif-1', router=rtr, area_id='1')
    ospfif.set_area_type('nssa')
    ospfif.auth_key = 'password'
    ospfif.int_policy_name = ifpol.name
    ospfif.auth_keyid = '1'
    ospfif.auth_type = 'simple'
    tenant.attach(ospfif)
    ospfif.networks.append('55.5.5.0/24')
    ospfif.attach(l3if)
    contract1 = Contract('contract-1')
    outside_epg = OutsideEPG('outepg', outside_l3)
    outside_epg.provide(contract1)
    contract2 = Contract('contract-2')
    outside_epg.consume(contract2)
    outside_l3.attach(ospfif)

    print(tenant.get_json())
    resp = session.push_to_apic(tenant.get_url(),
                                tenant.get_json())

    if not resp.ok:
        print('%% Error: Could not push configuration to APIC')
        print(resp.text)
Beispiel #4
0
def main():
    """
    Main execution routine

    :return: None
    """
    creds = Credentials('apic')
    creds.add_argument('--tenant', help='The name of Tenant')
    creds.add_argument('--vrf', help='The name of VRF')
    creds.add_argument('--bd', help='The name of BridgeDomain')
    creds.add_argument('--address', help='Subnet IPv4 Address')
    creds.add_argument('--scope', help='The scope of subnet ("public", "private", "shared", "public,shared", "private,shared", "shared,public", "shared,private")')
    creds.add_argument('--json', const='false', nargs='?', help='Json output only')

    args = creds.get()
    session = Session(args.url, args.login, args.password)
    session.login()

    tenant = Tenant(args.tenant)
    vrf = Context(args.vrf)
    bd = BridgeDomain(args.bd, tenant)
    bd.add_context(vrf)

    if args.address is None:
        bd.set_arp_flood('yes')
        bd.set_unicast_route('no')
    else:
        bd.set_arp_flood('no')
        bd.set_unicast_route('yes')

        subnet = Subnet('', bd)
        subnet.addr = args.address

        if args.scope is None:
            subnet.set_scope("private")
        else:
            subnet.set_scope(args.scope)

    if args.json:
        print(tenant.get_json())
    else:
        resp = session.push_to_apic(tenant.get_url(),
                                    tenant.get_json())

        if not resp.ok:
            print('%% Error: Could not push configuration to APIC')
            print(resp.text)
def main():
    """
    Main execution routine

    :return: None
    """
    creds = Credentials('apic')
    args = creds.get()
    session = Session(args.url, args.login, args.password)
    session.login()

    tenant = Tenant('cisco')
    context = Context('ctx1', tenant)
    outside_l3 = OutsideL3('out-1', tenant)
    phyif = Interface('eth', '1', '101', '1', '46')
    phyif.speed = '1G'
    l2if = L2Interface('eth 1/101/1/46', 'vlan', '1')
    l2if.attach(phyif)
    l3if = L3Interface('l3if')
    l3if.set_l3if_type('l3-port')
    l3if.set_addr('1.1.1.2/30')
    l3if.add_context(context)
    l3if.attach(l2if)
    bgpif = BGPSession('test', peer_ip='1.1.1.1', node_id='101')
    bgpif.router_id = '172.1.1.1'
    bgpif.attach(l3if)
    bgpif.options = 'send-ext-com'
    bgpif.networks.append('0.0.0.0/0')
    contract1 = Contract('icmp')
    outside_epg = OutsideEPG('outepg', outside_l3)
    outside_epg.provide(contract1)
    outside_l3.add_context(context)
    outside_epg.consume(contract1)
    outside_l3.attach(bgpif)
    bgp_json = bgpif.get_json()

    resp = session.push_to_apic(tenant.get_url(),
                                tenant.get_json())

    if not resp.ok:
        print('%% Error: Could not push configuration to APIC')
        print(resp.text)
Beispiel #6
0
def main():
    """
    Main execution routine

    :return: None
    """
    creds = Credentials('apic')
    args = creds.get()
    session = Session(args.url, args.login, args.password)
    session.login()

    tenant = Tenant('cisco')
    context = Context('ctx1', tenant)
    outside_l3 = OutsideL3('out-1', tenant)
    phyif = Interface('eth', '1', '101', '1', '46')
    phyif.speed = '1G'
    l2if = L2Interface('eth 1/101/1/46', 'vlan', '1')
    l2if.attach(phyif)
    l3if = L3Interface('l3if')
    l3if.set_l3if_type('l3-port')
    l3if.set_addr('1.1.1.2/30')
    l3if.add_context(context)
    l3if.attach(l2if)
    bgpif = BGPSession('test', peer_ip='1.1.1.1', node_id='101')
    bgpif.router_id = '172.1.1.1'
    bgpif.attach(l3if)
    bgpif.options = 'send-ext-com'
    bgpif.networks.append('0.0.0.0/0')
    contract1 = Contract('icmp')
    outside_epg = OutsideEPG('outepg', outside_l3)
    outside_epg.provide(contract1)
    outside_l3.add_context(context)
    outside_epg.consume(contract1)
    outside_l3.attach(bgpif)
    bgp_json = bgpif.get_json()

    resp = session.push_to_apic(tenant.get_url(), tenant.get_json())

    if not resp.ok:
        print('%% Error: Could not push configuration to APIC')
        print(resp.text)
class Monitor(threading.Thread):
    """
    Thread responsible for monitoring EPG-to-Contract relations.
    """
    def __init__(self, cdb):
        threading.Thread.__init__(self)
        self.cdb = cdb
        self._monitor_frequency = 1
        self._exit = False
        self._relation_subscriptions = []
        self._inheritance_tag_subscriptions = []
        self._subnet_subscriptions = []
        self._relations = RelationDB()
        self._inheritance_tags = TagDB()
        self._subnets = SubnetDB()
        self._old_relations = {}
        self.apic = None

    def exit(self):
        """
        Indicate that the thread should exit.
        """
        self._exit = True

    def subscribe(self, policy):
        query_url = ''
        epg = policy.epg
        epg_data = (epg.tenant, epg.epg_container_name, epg.name)
        if epg.epg_container_type == 'app':
            query_url = '/api/mo/uni/tn-%s/ap-%s/epg-%s.json' % epg_data
        elif epg.epg_container_type == 'l3out':
            subnet_query_url = '/api/mo/uni/tn-%s/out-%s/instP-%s.json' % epg_data
            subnet_query_url += '?query-target=subtree&target-subtree-class=l3extSubnet'
            subnet_query_url += '&subscription=yes'
            if subnet_query_url not in self._subnet_subscriptions:
                self.apic.subscribe(subnet_query_url)
                self._subnet_subscriptions.append(subnet_query_url)
            query_url = '/api/mo/uni/tn-%s/out-%s/instP-%s.json' % epg_data
        elif epg.epg_container_type == 'l2out':
            query_url = '/api/mo/uni/tn-%s/l2out-%s/instP-%s.json' % epg_data
        query_url += '?query-target=subtree&target-subtree-class=fvRsProv,fvRsCons,fvRsProtBy,fvRsConsIf'
        query_url += '&subscription=yes'
        if query_url not in self._relation_subscriptions:
            self.apic.subscribe(query_url)
            self._relation_subscriptions.append(query_url)

    def connect_to_apic(self):
        logging.debug('Connecting to APIC...')
        # Connect to APIC
        apic_config = self.cdb.get_apic_config()
        url = apic_config.ip_address
        if apic_config.use_https:
            url = 'https://' + url
        else:
            url = 'http://' + url
        if self.apic is not None:
            logging.debug('APIC is previously connected')
        self.apic = Session(url, apic_config.user_name, apic_config.password)
        resp = self.apic.login()

        # TODO: need to clear out the databases first
        assert len(self._inheritance_tags.db) == 0

        # Get all of the subnets
        query_url = '/api/mo/uni.json?query-target=subtree&target-subtree-class=l3extSubnet'
        subnets = self.apic.get(query_url)
        for subnet in subnets.json()['imdata']:
            subnet_event = SubnetEvent(subnet)
            self._subnets.store_subnet_event(subnet_event)

        # Get all of the inherited relations
        tag_query_url = '/api/class/tagInst.json?query-target-filter=wcard(tagInst.name,"inherited:")'
        tags = self.apic.get(tag_query_url)
        for tag in tags.json()['imdata']:
            tag_event = TagEvent(tag)
            # Create a database entry for the inherited relations
            self._inheritance_tags.store_tag(tag_event)
        self._old_relations = self._inheritance_tags.get_relations()

        # Get all of the relations. We need this to track relations that are already present
        # i.e. configured but not through inheritance so that we can tell the difference
        query_url = '/api/mo/uni.json?query-target=subtree&target-subtree-class=fvRsProv,fvRsCons,fvRsProtBy,fvRsConsIf'
        relations = self.apic.get(query_url)
        for relation in relations.json()['imdata']:
            # Skip any in-band and out-of-band interfaces
            if '/mgmtp-' in relation[relation.keys()[0]]['attributes']['dn']:
                continue
            self._relations.store_relation(RelationEvent(relation))

        # Get all of the policies that are inherited from but not inheriting
        parent_only_policies = []
        for policy in self.cdb.get_inheritance_policies():
            inherited_from = False
            if policy.allowed and not policy.enabled:
                for child_policy in self.cdb.get_inheritance_policies():
                    if child_policy.has_inherit_from(
                    ) and child_policy.inherit_from == policy.epg:
                        inherited_from = True
            if inherited_from:
                parent_only_policies.append(policy)

        # Issue all of the subscriptions
        for policy in self.cdb.get_inheritance_policies():
            self.subscribe(policy)
        for parent_only_policy in parent_only_policies:
            self.subscribe(parent_only_policy)
        tag_query_url += '&subscription=yes'
        self.apic.subscribe(tag_query_url)
        self._inheritance_tag_subscriptions.append(tag_query_url)

    def _does_tenant_have_contract(self,
                                   tenant_name,
                                   contract_name,
                                   contract_type='brc'):
        logging.debug('tenant: %s contract: %s contract_type: %s', tenant_name,
                      contract_name, contract_type)
        query_url = '/api/mo/uni/tn-%s/%s-%s.json' % (
            tenant_name, contract_type, contract_name)
        resp = self.apic.get(query_url)
        return resp.ok and int(resp.json()['totalCount']) > 0

    def does_tenant_have_contract_if(self, tenant_name, contract_if_name):
        return self._does_tenant_have_contract(tenant_name,
                                               contract_if_name,
                                               contract_type='cif')

    def does_tenant_have_contract(self, tenant_name, contract_name):
        return self._does_tenant_have_contract(tenant_name, contract_name)

    def _add_inherited_relation(self, tenants, epg, relation, deleted=False):
        tenant_found = False

        # Find the tenant. Add if necessary
        for tenant in tenants:
            if tenant.name == epg.tenant:
                tenant_found = True
                break
        if not tenant_found:
            tenant = Tenant(epg.tenant)
            tenants.append(tenant)

        # Find the EPG Container. Add if necessary
        if epg.is_l3out():
            epg_container_class = OutsideL3
        else:
            epg_container_class = AppProfile
        epg_containers = tenant.get_children(only_class=epg_container_class)
        epg_container_found = False
        for epg_container in epg_containers:
            if epg_container.name == epg.epg_container_name:
                epg_container_found = True
                break
        if not epg_container_found:
            epg_container = epg_container_class(epg.epg_container_name, tenant)

        # Find the EPG. Add if necessary
        if epg.is_l3out():
            epg_class = OutsideEPG
        else:
            epg_class = EPG
        epgs = tenant.get_children(only_class=epg_class)
        epg_found = False
        for tenant_epg in epgs:
            if tenant_epg.name == epg.name:
                epg_found = True
                break
        if not epg_found:
            tenant_epg = epg_class(epg.name, epg_container)

        # Add the relation
        (relation_type, relation_name) = relation
        if relation_type == 'fvRsProv':
            contract = Contract(relation_name, tenant)
            tenant_epg.provide(contract)
            if deleted:
                tenant_epg.provide(contract)
                tenant_epg.dont_provide(contract)
        elif relation_type == 'fvRsCons':
            contract = Contract(relation_name, tenant)
            tenant_epg.consume(contract)
            if deleted:
                tenant_epg.consume(contract)
                tenant_epg.dont_consume(contract)
        elif relation_type == 'fvRsConsIf':
            contract_interface = ContractInterface(relation_name, tenant)
            tenant_epg.consume_cif(contract_interface)
            if deleted:
                tenant_epg.consume_cif(contract_interface)
                tenant_epg.dont_consume_cif(contract_interface)
        elif relation_type == 'fvRsProtBy':
            taboo = Taboo(relation_name, tenant)
            tenant_epg.protect(taboo)
            if deleted:
                tenant_epg.protect(taboo)
                tenant_epg.dont_protect(taboo)
        tenant_epg.add_tag('inherited:%s:%s' % (relation_type, relation_name))
        if deleted:
            tenant_epg.delete_tag('inherited:%s:%s' %
                                  (relation_type, relation_name))
        return tenants

    def add_inherited_relation(self, tenants, epg, relation):
        return self._add_inherited_relation(tenants, epg, relation)

    def remove_inherited_relation(self, tenants, epg, relation):
        return self._add_inherited_relation(tenants,
                                            epg,
                                            relation,
                                            deleted=True)

    def _calculate_relations_for_l3out_policy(self, inheritance_policy):
        logging.debug('_calculate_relations_for_l3out_policy: %s',
                      inheritance_policy)
        # Get all of the EPGs covering this policy's EPG's subnets
        covering_epgs = self._subnets.get_all_covering_epgs(
            inheritance_policy.epg)

        # Remove any EPGs that are not allowed to be inherited
        for covering_epg in covering_epgs:
            if not self.cdb.is_inheritance_allowed(covering_epg):
                covering_epgs.remove(covering_epg)

        # Get all of the relations for the remaining covering EPGs
        relations = []
        for covering_epg in covering_epgs:
            epg_relations = self._relations.get_relations_for_epg(covering_epg)
            for epg_relation in epg_relations:
                if epg_relation not in relations:
                    relations.append(epg_relation)

        logging.debug('Relations to be inherited: %s', relations)

        # Need to add any configured relations
        configured_relations = self._relations.get_relations_for_epg(
            inheritance_policy.epg)
        for configured_relation in configured_relations:
            if configured_relation not in relations:
                logging.debug('Adding configured relation: %s',
                              configured_relation)
                if not self._inheritance_tags.is_inherited(
                        inheritance_policy.epg, configured_relation):
                    relations.append(configured_relation)
        return relations

    def _calculate_relations_for_app_policy(self, inheritance_policy):
        logging.debug('policy: %s', inheritance_policy)
        relations = []
        # Check if this policy is even inheritance enabled
        if not inheritance_policy.has_inherit_from():
            logging.warning('EPG is not inheriting from a parent EPG')
            return relations
        # Get the EPG that this policy is inheriting from
        parent_epg = inheritance_policy.inherit_from
        # Is inheritance allowed on that EPG ?
        if not self.cdb.is_inheritance_allowed(parent_epg):
            logging.warning('Parent EPG policy does not allow inheritance')
            return relations
        # Get the relations belonging to that EPG
        return self._relations.get_relations_for_epg(parent_epg)

    def calculate_relations(self):
        relations = {}
        for inheritance_policy in self.cdb.get_inheritance_policies():
            if not inheritance_policy.enabled:
                continue
            if inheritance_policy.epg.is_l3out():
                epg_relations = self._calculate_relations_for_l3out_policy(
                    inheritance_policy)
            else:
                # TODO: may eventually need to process l2out
                epg_relations = self._calculate_relations_for_app_policy(
                    inheritance_policy)
            relations[inheritance_policy.epg.get_json()] = epg_relations
        return relations

    def process_relation_event(self, event):
        logging.debug('process_event EVENT: %s', event.event)
        self._relations.store_relation(event)

    def process_subnet_event(self, event):
        logging.debug('Received subnet event: %s', event)
        # Store the subnet in the SubnetDB
        self._subnets.store_subnet_event(event)

    def process_inheritance_tag_event(self, event):
        logging.debug('Received subnet event: %s', event)
        # Store the tag in the TagDB
        self._inheritance_tags.store_tag(event)

    def _process_events(self, old_relations):
        while self.apic is None:
            pass

        if old_relations is None:
            old_relations = self._inheritance_tags.get_relations()

        # Check for any tag events
        for subscription in self._inheritance_tag_subscriptions:
            while self.apic.has_events(subscription):
                event = TagEvent(
                    self.apic.get_event(subscription)['imdata'][0])
                self.process_inheritance_tag_event(event)

        # Check for relation events
        for subscription in self._relation_subscriptions:
            while self.apic.has_events(subscription):
                event = RelationEvent(
                    self.apic.get_event(subscription)['imdata'][0])
                self.process_relation_event(event)

        # Check for subnet events
        for subscription in self._subnet_subscriptions:
            while self.apic.has_events(subscription):
                event = SubnetEvent(
                    self.apic.get_event(subscription)['imdata'][0])
                self.process_subnet_event(event)

        # Calculate the new set of relations
        new_relations = self.calculate_relations()

        for old_epg in old_relations:
            logging.debug(old_epg)
        for new_epg in new_relations:
            logging.debug(new_epg)

        # Compare the old and the new relations for changes
        tenants = []
        for new_epg in new_relations:
            if new_epg not in old_relations:
                # New EPG, so we need to add all of the relations
                for new_relation in new_relations[new_epg]:
                    if self._inheritance_tags.is_inherited(
                            EPGPolicy(json.loads(new_epg)), new_relation):
                        # If it's inherited, but we don't have the relation. We are likely coming up and not populated
                        # the old_relations yet
                        pass
                    # If just configured, we will have a relationDB entry. Otherwise, we need to inherit it
                    if self._relations.has_relation_for_epg(
                            EPGPolicy(json.loads(new_epg)), new_relation):
                        continue
                    tenants = self.add_inherited_relation(
                        tenants, EPGPolicy(json.loads(new_epg)), new_relation)
            else:
                # Handle any new added relations
                for new_relation in new_relations[new_epg]:
                    if new_relation not in old_relations[new_epg]:
                        if self._relations.has_relation_for_epg(
                                EPGPolicy(json.loads(new_epg)), new_relation):
                            continue
                        tenants = self.add_inherited_relation(
                            tenants, EPGPolicy(json.loads(new_epg)),
                            new_relation)
                # Handle any deleted relations
                for old_relation in old_relations[new_epg]:
                    if old_relation not in new_relations[new_epg]:
                        if self._inheritance_tags.is_inherited(
                                EPGPolicy(json.loads(new_epg)), old_relation):
                            tenants = self.remove_inherited_relation(
                                tenants, EPGPolicy(json.loads(new_epg)),
                                old_relation)
                        else:
                            # Must have been configured and manually deleted
                            pass
        for old_epg in old_relations:
            if old_epg not in new_relations:
                for old_relation in old_relations[old_epg]:
                    if self._inheritance_tags.is_inherited(
                            EPGPolicy(json.loads(old_epg)), old_relation):
                        tenants = self.remove_inherited_relation(
                            tenants, EPGPolicy(json.loads(old_epg)),
                            old_relation)

        # Push the necessary config to the APIC
        for tenant in tenants:
            tenant_json = tenant.get_json()
            # Check that the tenant actually has the contracts since they may actually be tenant common contracts.
            # If tenant common is used, we need to clean up the tenant JSON to not create an empty contract within
            # this tenant
            for child in tenant_json['fvTenant']['children']:
                if 'vzBrCP' in child:
                    if not self.does_tenant_have_contract(
                            tenant.name,
                            child['vzBrCP']['attributes']['name']):
                        tenant_json['fvTenant']['children'].remove(child)
                elif 'vzCPIf' in child:
                    if not self.does_tenant_have_contract_if(
                            tenant.name,
                            child['vzCPIf']['attributes']['name']):
                        tenant_json['fvTenant']['children'].remove(child)
            logging.debug('Pushing tenant configuration to the APIC: %s',
                          tenant_json)
            resp = self.apic.push_to_apic(tenant.get_url(), tenant_json)
            if resp.ok:
                logging.debug('Pushed to APIC successfully')
            else:
                logging.error('Error pushing to APIC', resp.text)
        return new_relations

    def run(self):
        loop_count = 0
        accelerated_cleanup_done = False
        while not self._exit:
            time.sleep(self._monitor_frequency)
            self._old_relations = self._process_events(self._old_relations)
from acitoolkit.acitoolkit import Session, Credentials, Tenant

creds = Credentials('apic', 'Opis co skrypt robi.')
args = creds.get()

session = Session(args.url, args.login, args.password)

resp = session.login()
if not resp.ok:
    print 'Could not login to APIC'

tenant = Tenant('mytenat')

resp = session.push_to_apic(tenant.get_url(), tenant.get_json())
if not resp.ok:
    print 'Could not push configuration to APIC'
    print resp.text

tenants = Tenant.get(session)
for tenant in tenants:
    print tenant.name

session.close()
Beispiel #9
0
                                sn = existing_tenants[t]['bds'][b]['subnets'][s]
                                
                                # Mark the subnet as deleted
                                sn.mark_as_deleted()
                                
                                # Add the corresponding subnet to the BD so 
                                # we can push it with the deleted status
                                bd.add_child(sn)
                            else:
                                print(" |_ Existing Subnet %s/%s/%s will be kept intact because no '--remove yes' was supplied." % (t,b,s))

    if args.commit == True:
        for tenant_name in tenants_modified:
            output("[+] Pushing configuration for Tenant '%s'" % tenant_name)
            tenant = tenants_modified[tenant_name]
            debug(tenant.get_json())
            r = session.push_to_apic(tenant.get_url(), data=tenant.get_json())
            if r.status_code>299:
                try:
                    resp_data = json.loads(r.text)
                    errmsg = resp_data['imdata'][0]['error']['attributes']['text']
                except:
                    errmsg = r.text
                fatal("[E] ERROR: %s" % errmsg)
            else:
                output("[+] Configuration for Tenant '%s' pushed successfully" % tenant_name)
    else:
        output("[+] No configuration pushed because '--commit yes' not supplied.")

    sys.exit(0)
Beispiel #10
0
class Monitor(threading.Thread):
    """
    Thread responsible for monitoring EPG-to-Contract relations.
    """
    def __init__(self, cdb):
        threading.Thread.__init__(self)
        self.cdb = cdb
        self._monitor_frequency = 1
        self._exit = False
        self._relation_subscriptions = []
        self._inheritance_tag_subscriptions = []
        self._subnet_subscriptions = []
        self._relations = RelationDB()
        self._inheritance_tags = TagDB()
        self._subnets = SubnetDB()
        self._old_relations = {}
        self.apic = None

    def exit(self):
        """
        Indicate that the thread should exit.
        """
        self._exit = True

    def subscribe(self, policy):
        query_url = ''
        epg = policy.epg
        epg_data = (epg.tenant, epg.epg_container_name, epg.name)
        if epg.epg_container_type == 'app':
            query_url = '/api/mo/uni/tn-%s/ap-%s/epg-%s.json' % epg_data
        elif epg.epg_container_type == 'l3out':
            subnet_query_url = '/api/mo/uni/tn-%s/out-%s/instP-%s.json' % epg_data
            subnet_query_url += '?query-target=subtree&target-subtree-class=l3extSubnet'
            subnet_query_url += '&subscription=yes'
            if subnet_query_url not in self._subnet_subscriptions:
                self.apic.subscribe(subnet_query_url)
                self._subnet_subscriptions.append(subnet_query_url)
            query_url = '/api/mo/uni/tn-%s/out-%s/instP-%s.json' % epg_data
        elif epg.epg_container_type == 'l2out':
            query_url = '/api/mo/uni/tn-%s/l2out-%s/instP-%s.json' % epg_data
        query_url += '?query-target=subtree&target-subtree-class=fvRsProv,fvRsCons,fvRsProtBy,fvRsConsIf'
        query_url += '&subscription=yes'
        if query_url not in self._relation_subscriptions:
            self.apic.subscribe(query_url)
            self._relation_subscriptions.append(query_url)

    def connect_to_apic(self):
        logging.debug('Connecting to APIC...')
        # Connect to APIC
        apic_config = self.cdb.get_apic_config()
        url = apic_config.ip_address
        if apic_config.use_https:
            url = 'https://' + url
        else:
            url = 'http://' + url
        if self.apic is not None:
            logging.debug('APIC is previously connected')
        self.apic = Session(url, apic_config.user_name, apic_config.password)
        resp = self.apic.login()

        # TODO: need to clear out the databases first
        assert len(self._inheritance_tags.db) == 0

        # Get all of the subnets
        query_url = '/api/mo/uni.json?query-target=subtree&target-subtree-class=l3extSubnet'
        subnets = self.apic.get(query_url)
        for subnet in subnets.json()['imdata']:
            subnet_event = SubnetEvent(subnet)
            self._subnets.store_subnet_event(subnet_event)

        # Get all of the inherited relations
        tag_query_url = '/api/class/tagInst.json?query-target-filter=wcard(tagInst.name,"inherited:")'
        tags = self.apic.get(tag_query_url)
        for tag in tags.json()['imdata']:
            tag_event = TagEvent(tag)
            # Create a database entry for the inherited relations
            self._inheritance_tags.store_tag(tag_event)
        self._old_relations = self._inheritance_tags.get_relations()

        # Get all of the relations. We need this to track relations that are already present
        # i.e. configured but not through inheritance so that we can tell the difference
        query_url = '/api/mo/uni.json?query-target=subtree&target-subtree-class=fvRsProv,fvRsCons,fvRsProtBy,fvRsConsIf'
        relations = self.apic.get(query_url)
        for relation in relations.json()['imdata']:
            # Skip any in-band and out-of-band interfaces
            if '/mgmtp-' in relation[relation.keys()[0]]['attributes']['dn']:
                continue
            self._relations.store_relation(RelationEvent(relation))

        # Get all of the policies that are inherited from but not inheriting
        parent_only_policies = []
        for policy in self.cdb.get_inheritance_policies():
            inherited_from = False
            if policy.allowed and not policy.enabled:
                for child_policy in self.cdb.get_inheritance_policies():
                    if child_policy.has_inherit_from() and child_policy.inherit_from == policy.epg:
                        inherited_from = True
            if inherited_from:
                parent_only_policies.append(policy)

        # Issue all of the subscriptions
        for policy in self.cdb.get_inheritance_policies():
            self.subscribe(policy)
        for parent_only_policy in parent_only_policies:
            self.subscribe(parent_only_policy)
        tag_query_url += '&subscription=yes'
        self.apic.subscribe(tag_query_url)
        self._inheritance_tag_subscriptions.append(tag_query_url)

    def _does_tenant_have_contract(self, tenant_name, contract_name, contract_type='brc'):
        logging.debug('tenant: %s contract: %s contract_type: %s',
                      tenant_name, contract_name, contract_type)
        query_url = '/api/mo/uni/tn-%s/%s-%s.json' % (tenant_name,
                                                      contract_type,
                                                      contract_name)
        resp = self.apic.get(query_url)
        return resp.ok and int(resp.json()['totalCount']) > 0

    def does_tenant_have_contract_if(self, tenant_name, contract_if_name):
        return self._does_tenant_have_contract(tenant_name,
                                               contract_if_name,
                                               contract_type='cif')

    def does_tenant_have_contract(self, tenant_name, contract_name):
        return self._does_tenant_have_contract(tenant_name,
                                               contract_name)

    def _add_inherited_relation(self, tenants, epg, relation, deleted=False):
        tenant_found = False

        # Find the tenant. Add if necessary
        for tenant in tenants:
            if tenant.name == epg.tenant:
                tenant_found = True
                break
        if not tenant_found:
            tenant = Tenant(epg.tenant)
            tenants.append(tenant)

        # Find the EPG Container. Add if necessary
        if epg.is_l3out():
            epg_container_class = OutsideL3
        else:
            epg_container_class = AppProfile
        epg_containers = tenant.get_children(only_class=epg_container_class)
        epg_container_found = False
        for epg_container in epg_containers:
            if epg_container.name == epg.epg_container_name:
                epg_container_found = True
                break
        if not epg_container_found:
            epg_container = epg_container_class(epg.epg_container_name, tenant)

        # Find the EPG. Add if necessary
        if epg.is_l3out():
            epg_class = OutsideEPG
        else:
            epg_class = EPG
        epgs = tenant.get_children(only_class=epg_class)
        epg_found = False
        for tenant_epg in epgs:
            if tenant_epg.name == epg.name:
                epg_found = True
                break
        if not epg_found:
            tenant_epg = epg_class(epg.name, epg_container)

        # Add the relation
        (relation_type, relation_name) = relation
        if relation_type == 'fvRsProv':
            contract = Contract(relation_name, tenant)
            tenant_epg.provide(contract)
            if deleted:
                tenant_epg.provide(contract)
                tenant_epg.dont_provide(contract)
        elif relation_type == 'fvRsCons':
            contract = Contract(relation_name, tenant)
            tenant_epg.consume(contract)
            if deleted:
                tenant_epg.consume(contract)
                tenant_epg.dont_consume(contract)
        elif relation_type == 'fvRsConsIf':
            contract_interface = ContractInterface(relation_name, tenant)
            tenant_epg.consume_cif(contract_interface)
            if deleted:
                tenant_epg.consume_cif(contract_interface)
                tenant_epg.dont_consume_cif(contract_interface)
        elif relation_type == 'fvRsProtBy':
            taboo = Taboo(relation_name, tenant)
            tenant_epg.protect(taboo)
            if deleted:
                tenant_epg.protect(taboo)
                tenant_epg.dont_protect(taboo)
        tenant_epg.add_tag('inherited:%s:%s' % (relation_type, relation_name))
        if deleted:
            tenant_epg.delete_tag('inherited:%s:%s' % (relation_type, relation_name))
        return tenants

    def add_inherited_relation(self, tenants, epg, relation):
        return self._add_inherited_relation(tenants, epg, relation)

    def remove_inherited_relation(self, tenants, epg, relation):
        return self._add_inherited_relation(tenants, epg, relation, deleted=True)

    def _calculate_relations_for_l3out_policy(self, inheritance_policy):
        logging.debug('_calculate_relations_for_l3out_policy: %s', inheritance_policy)
        # Get all of the EPGs covering this policy's EPG's subnets
        covering_epgs = self._subnets.get_all_covering_epgs(inheritance_policy.epg)

        # Remove any EPGs that are not allowed to be inherited
        for covering_epg in covering_epgs:
            if not self.cdb.is_inheritance_allowed(covering_epg):
                covering_epgs.remove(covering_epg)

        # Get all of the relations for the remaining covering EPGs
        relations = []
        for covering_epg in covering_epgs:
            epg_relations = self._relations.get_relations_for_epg(covering_epg)
            for epg_relation in epg_relations:
                if epg_relation not in relations:
                    relations.append(epg_relation)

        logging.debug('Relations to be inherited: %s', relations)

        # Need to add any configured relations
        configured_relations = self._relations.get_relations_for_epg(inheritance_policy.epg)
        for configured_relation in configured_relations:
            if configured_relation not in relations:
                logging.debug('Adding configured relation: %s', configured_relation)
                if not self._inheritance_tags.is_inherited(inheritance_policy.epg, configured_relation):
                    relations.append(configured_relation)
        return relations

    def _calculate_relations_for_app_policy(self, inheritance_policy):
        logging.debug('policy: %s', inheritance_policy)
        relations = []
        # Check if this policy is even inheritance enabled
        if not inheritance_policy.has_inherit_from():
            logging.warning('EPG is not inheriting from a parent EPG')
            return relations
        # Get the EPG that this policy is inheriting from
        parent_epg = inheritance_policy.inherit_from
        # Is inheritance allowed on that EPG ?
        if not self.cdb.is_inheritance_allowed(parent_epg):
            logging.warning('Parent EPG policy does not allow inheritance')
            return relations
        # Get the relations belonging to that EPG
        return self._relations.get_relations_for_epg(parent_epg)

    def calculate_relations(self):
        relations = {}
        for inheritance_policy in self.cdb.get_inheritance_policies():
            if not inheritance_policy.enabled:
                continue
            if inheritance_policy.epg.is_l3out():
                epg_relations = self._calculate_relations_for_l3out_policy(inheritance_policy)
            else:
                # TODO: may eventually need to process l2out
                epg_relations = self._calculate_relations_for_app_policy(inheritance_policy)
            relations[inheritance_policy.epg.get_json()] = epg_relations
        return relations

    def process_relation_event(self, event):
        logging.debug('process_event EVENT: %s', event.event)
        self._relations.store_relation(event)

    def process_subnet_event(self, event):
        logging.debug('Received subnet event: %s', event)
        # Store the subnet in the SubnetDB
        self._subnets.store_subnet_event(event)

    def process_inheritance_tag_event(self, event):
        logging.debug('Received subnet event: %s', event)
        # Store the tag in the TagDB
        self._inheritance_tags.store_tag(event)

    def _process_events(self, old_relations):
        while self.apic is None:
            pass

        if old_relations is None:
            old_relations = self._inheritance_tags.get_relations()

        # Check for any tag events
        for subscription in self._inheritance_tag_subscriptions:
            while self.apic.has_events(subscription):
                event = TagEvent(self.apic.get_event(subscription)['imdata'][0])
                self.process_inheritance_tag_event(event)

        # Check for relation events
        for subscription in self._relation_subscriptions:
            while self.apic.has_events(subscription):
                event = RelationEvent(self.apic.get_event(subscription)['imdata'][0])
                self.process_relation_event(event)

        # Check for subnet events
        for subscription in self._subnet_subscriptions:
            while self.apic.has_events(subscription):
                event = SubnetEvent(self.apic.get_event(subscription)['imdata'][0])
                self.process_subnet_event(event)

        # Calculate the new set of relations
        new_relations = self.calculate_relations()

        for old_epg in old_relations:
            logging.debug(old_epg)
        for new_epg in new_relations:
            logging.debug(new_epg)

        # Compare the old and the new relations for changes
        tenants = []
        for new_epg in new_relations:
            if new_epg not in old_relations:
                # New EPG, so we need to add all of the relations
                for new_relation in new_relations[new_epg]:
                    if self._inheritance_tags.is_inherited(EPGPolicy(json.loads(new_epg)), new_relation):
                        # If it's inherited, but we don't have the relation. We are likely coming up and not populated
                        # the old_relations yet
                        pass
                    # If just configured, we will have a relationDB entry. Otherwise, we need to inherit it
                    if self._relations.has_relation_for_epg(EPGPolicy(json.loads(new_epg)), new_relation):
                        continue
                    tenants = self.add_inherited_relation(tenants, EPGPolicy(json.loads(new_epg)), new_relation)
            else:
                # Handle any new added relations
                for new_relation in new_relations[new_epg]:
                    if new_relation not in old_relations[new_epg]:
                        if self._relations.has_relation_for_epg(EPGPolicy(json.loads(new_epg)), new_relation):
                            continue
                        tenants = self.add_inherited_relation(tenants, EPGPolicy(json.loads(new_epg)), new_relation)
                # Handle any deleted relations
                for old_relation in old_relations[new_epg]:
                    if old_relation not in new_relations[new_epg]:
                        if self._inheritance_tags.is_inherited(EPGPolicy(json.loads(new_epg)), old_relation):
                            tenants = self.remove_inherited_relation(tenants, EPGPolicy(json.loads(new_epg)), old_relation)
                        else:
                            # Must have been configured and manually deleted
                            pass
        for old_epg in old_relations:
            if old_epg not in new_relations:
                for old_relation in old_relations[old_epg]:
                    if self._inheritance_tags.is_inherited(EPGPolicy(json.loads(old_epg)), old_relation):
                        tenants = self.remove_inherited_relation(tenants, EPGPolicy(json.loads(old_epg)), old_relation)

        # Push the necessary config to the APIC
        for tenant in tenants:
            tenant_json = tenant.get_json()
            # Check that the tenant actually has the contracts since they may actually be tenant common contracts.
            # If tenant common is used, we need to clean up the tenant JSON to not create an empty contract within
            # this tenant
            for child in tenant_json['fvTenant']['children']:
                if 'vzBrCP' in child:
                    if not self.does_tenant_have_contract(tenant.name, child['vzBrCP']['attributes']['name']):
                        tenant_json['fvTenant']['children'].remove(child)
                elif 'vzCPIf' in child:
                    if not self.does_tenant_have_contract_if(tenant.name, child['vzCPIf']['attributes']['name']):
                        tenant_json['fvTenant']['children'].remove(child)
            logging.debug('Pushing tenant configuration to the APIC: %s', tenant_json)
            resp = self.apic.push_to_apic(tenant.get_url(), tenant_json)
            if resp.ok:
                logging.debug('Pushed to APIC successfully')
            else:
                logging.error('Error pushing to APIC', resp.text)
        return new_relations

    def run(self):
        loop_count = 0
        accelerated_cleanup_done = False
        while not self._exit:
            time.sleep(self._monitor_frequency)
            self._old_relations = self._process_events(self._old_relations)