Exemplo n.º 1
0
def Create_Contract(aci_sheet, row):
    # call login function and return session
    session = apic_login()

    # create variables by importing values from spreadsheet
    tn_name = ACI.Tenant(aci_sheet.cell_value(row, 1))
    print tn_name
    contract_name = ACI.Contract(aci_sheet.cell_value(row, 2), tn_name)
    print contract_name
    filter_entry = ACI.FilterEntry('PythonFilter',
                                   applyToFrag='no',
                                   arpOpc='unspecified',
                                   dFromPort=str(aci_sheet.cell_value(row, 8)),
                                   dToPort=str(aci_sheet.cell_value(row, 9)),
                                   etherT='ip',
                                   prot=(aci_sheet.cell_value(row, 7)),
                                   sFromPort='1',
                                   sToPort='65535',
                                   tcpRules='unspecified',
                                   parent=contract_name)
    print filter_entry

    resp = session.push_to_apic(tn_name.get_url(), data=tn_name.get_json())
    if resp.ok:
        print 'Contract %s deployed' % contract_name
        print '=' * 20
    else:
        print 'contract %s not deployed' % contract_name
Exemplo n.º 2
0
def lab4(course_partecipants, tenant_list = []):
    
    new_tenant_list = []
    for cp in range(1, course_partecipants+1):
        
        tenant = tenant_list[cp-1]

        # Define a contract with a single entry
        contract = aci.Contract("permit-icmp", tenant)
        entry1 = aci.FilterEntry("icmp", 
                                parent=contract,
                                applyToFrag='no',
                                etherT='ip',
                                prot='icmp')
        
        # Apply contract in both directions
        
        ## Get EPGs 
        epg1 = get_epg("EPG100",tenant, "AP{}".format(cp))
        epg2 = get_epg("EPG200",tenant, "AP{}".format(cp))

        ## apply from epg1 to epg2
        epg1.provide(contract)
        epg2.consume(contract)

        ## apply from epg2 to epg1
        epg1.consume(contract)
        epg2.provide(contract)

        new_tenant_list.append(tenant)

    return new_tenant_list
Exemplo n.º 3
0
def main():
    """
    Main create tenant routine
    :return: None
    """
    # Get all the arguments
    description = 'It logs in to the APIC and will create the tenant.'
    creds = aci.Credentials('apic', description)
    creds.add_argument('-t',
                       '--tenant',
                       help='The name of tenant',
                       default=DEFAULT_TENANT_NAME)
    creds.add_argument('-c',
                       '--contract',
                       help='The name of contract',
                       default=DEFAULT_CONTRACT_NAME)
    creds.add_argument('-s',
                       '--contract_sub',
                       help='The name of contract \
                       subject',
                       default=DEFAULT_CONTRACT_SUB_NAME)
    creds.add_argument('-f',
                       '--filter',
                       help='The name of filter',
                       default=DEFAULT_CONTRACT_SUB_NAME)
    args = creds.get()

    # Login to the APIC
    session = aci.Session(args.url, args.login, args.password)
    resp = session.login()
    if not resp.ok:
        print('%% Could not login to APIC')

    # Create the Tenant
    tenant = aci.Tenant(args.tenant)

    # Create Contract
    contract = aci.Contract(args.contract, tenant)
    contract_sub = aci.ContractSubject(args.contract_sub, contract)
    # Create Filter
    filter = aci.Filter(args.filter, contract_sub)

    # Push the Contract to the APIC
    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)
Exemplo n.º 4
0
    def migration_tenant(self, tenant_name, app_name, provision=True):
        self.tenant = aci.Tenant(tenant_name)
        self.app = aci.AppProfile(app_name, self.tenant)
        self.context = aci.Context('default', self.tenant)

        self.contract = aci.Contract('allow-any', self.tenant)
        entry1 = aci.FilterEntry('default',
                                 applyToFrag='no',
                                 arpOpc='unspecified',
                                 etherT='unspecified',
                                 parent=self.contract)
        if provision:
            self.session.push_to_apic(self.tenant.get_url(),
                                      self.tenant.get_json())
        else:
            self.tenant.get_json()
        return self.tenant
Exemplo n.º 5
0
 def handle_create(self):
     tenant = aci.Tenant(self.tenant)
     contract = aci.Contract(str(self.properties['Contract']), tenant)
     rules = self.properties['Rules']
     logger.info(rules)
     for entry in rules:
         entry = str(entry)
         if entry == 'any':
             aci.FilterEntry(entry, etherT='unspecified', parent=contract)
             break
         protocol_port = entry.split('-')
         aci.FilterEntry(entry,
                         dFromPort=protocol_port[1],
                         dToPort=protocol_port[1],
                         etherT='ip',
                         prot=protocol_port[0],
                         parent=contract)
     url = tenant.get_url()
     data = tenant.get_json()
     logger.info(data)
     self.push_to_apic(url, data)
Exemplo n.º 6
0
def main():
    """
    Main create tenant routine
    :return: None
    """
    # Get all the arguments
    description = 'It logs in to the APIC and will create the tenant.'
    creds = aci.Credentials('apic', description)
    creds.add_argument('-t',
                       '--tenant',
                       help='The name of tenant',
                       default=DEFAULT_TENANT_NAME)
    creds.add_argument('-a',
                       '--app',
                       help='The name of application profile',
                       default=DEFAULT_APP_NAME)
    creds.add_argument('-e',
                       '--epg',
                       help='The name of EPG',
                       default=DEFAULT_EPG_NAME)
    creds.add_argument('-b',
                       '--bd',
                       help='The name of bridge domain',
                       default=DEFAULT_BD_NAME)
    creds.add_argument('-c',
                       '--contract',
                       help='The name of contract',
                       default=DEFAULT_CONTRACT_NAME)
    args = creds.get()

    # Login to the APIC
    session = aci.Session(args.url, args.login, args.password)
    resp = session.login()
    if not resp.ok:
        print('%% Could not login to APIC')

    # Create the Tenant
    tenant = aci.Tenant(args.tenant)

    # Create the Application Profile
    app = aci.AppProfile(args.app, tenant)

    # Create the EPG
    epg = aci.EPG(args.epg, app)

    # Create the Bridge Domain
    bd = aci.BridgeDomain(args.bd, tenant)

    epg.add_bd(bd)

    # Create Contract
    contract = aci.Contract(args.contract, tenant)

    # Provide the contract from 1 EPG and consume from the other
    epg.provide(contract)
    epg.consume(contract)

    # Push the Application Profile EPG to the APIC
    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)
Exemplo n.º 7
0
def Create_EPG(aci_sheet, row):
    # call login function and return session
    session = apic_login()

    # create variables by importing values from spreadsheet
    tn_name = ACI.Tenant(aci_sheet.cell_value(row, 1))
    ANP_name = ACI.AppProfile(aci_sheet.cell_value(row, 2), tn_name)
    EPG_name = ACI.EPG(aci_sheet.cell_value(row, 3), ANP_name)
    print EPG_name
    BD_name = ACI.BridgeDomain(aci_sheet.cell_value(row, 8), tn_name)
    contract = ACI.Contract(aci_sheet.cell_value(row, 9), tn_name)
    direction = aci_sheet.cell_value(row, 10)
    vmm_name = ACI.EPGDomain.get_by_name(session, (aci_sheet.cell_value(row, 7)))
    phy_domain_name = ACI.EPGDomain.get_by_name(session, (aci_sheet.cell_value(row, 6)))

    #associated EPG with Bridge Domain
    EPG_name.add_bd(BD_name)

    #associate EPG with VMM DOmain
    if vmm_name == None:
        print "no VMM domain selected"
    else:
        EPG_name.add_infradomain(vmm_name)
        print "EPG %s associated with vmm domain %s" % (EPG_name, vmm_name)

    #set EPG for intra-EPG isolation
    #EPG_name.set_intra_epg_isolation('enforced')

    # figure out direction of provider/consumer relationship
    if direction == 'consume':
        EPG_name.consume(contract)
    elif direction == 'provide':
        EPG_name.provide(contract)
    elif direction == '' or 'None':
        print 'No provider or consumer direction selected'

    # define the physical interfaces
    #single_port matches the format that should be on the spreadsheet for a single port with the pod,leaf,blade,port format
    single_port = re.compile('.*/.*/.*/.*')
    #The vpc_port matches any text
    vpc_port = re.compile('.*.')
    get_phys = aci_sheet.cell_value(row,4)

    #if the description matches the single port format, the string is split into the different values
    if single_port.match(get_phys) is not None:
        get_phys_split = get_phys.split('/')
        intf1 = ACI.Interface('eth', get_phys_split[0], get_phys_split[1], get_phys_split[2], get_phys_split[3])
        # define the encapsulation
        get_vlan_id = int(aci_sheet.cell_value(row, 5))
        print get_vlan_id
        static_encap_if = ACI.L2Interface('encap_' + str(get_vlan_id), 'vlan', get_vlan_id)

        # attach encap to physical interface
        static_encap_if.attach(intf1)

        # attach static port binding to EPG
        EPG_name.attach(static_encap_if)
        print 'EPG %s is associated with interface %s with encap vlan-' % (EPG_name, intf1, get_vlan_id)
    #if the vpc_port matches, the second sheet of the spreadsheet is consulted to get the physical interfaces of the VPC name
    elif vpc_port.match(get_phys):
        phys_aci_book = xlrd.open_workbook("EPG_Input.xlsx")
        phys_aci_sheet = phys_aci_book.sheet_by_index(1)
        for row in range(phys_aci_sheet.nrows):
            for column in range(phys_aci_sheet.ncols):
                if phys_aci_sheet.cell_value(row, column) == get_phys:
                    vpc_pair = phys_aci_sheet.cell_value(row,1)
                    interface_selector = phys_aci_sheet.cell_value(row,2)
                    vpc_leaf_split = vpc_pair.split('-')
                    intf_selector_split = interface_selector.split(',')
                    intf1 = ACI.Interface('eth', '1', vpc_leaf_split[0],'1',intf_selector_split[0])
                    intf2 = ACI.Interface('eth', '1', vpc_leaf_split[1],'1',intf_selector_split[0])
                    pc1 = ACI.PortChannel(get_phys)
                    pc1.attach(intf1)
                    pc1.attach(intf2)

                    # define the encapsulation
                    get_vlan_id = int(aci_sheet.cell_value(row, 5))
                    static_encap_if = ACI.L2Interface('encap_' + str(get_vlan_id), 'vlan', get_vlan_id)

                    # attach encap to physical interface
                    static_encap_if.attach(pc1)

                    # attach static port binding to EPG
                    EPG_name.attach(static_encap_if)
                    print 'EPG %s is associated with VPC %s with encap vlan-%s' % (EPG_name, get_phys, get_vlan_id)


    #associate EPG with physical domain
    if phy_domain_name == None:
        print 'no physical domain selected'
    else:
        EPG_name.add_infradomain(phy_domain_name)
        print 'EPG %s associated with physical domain %s' % (EPG_name, phy_domain_name)



    # ensure tenant exists and push configuration
    resp = session.push_to_apic(tn_name.get_url(), data=tn_name.get_json())
    if resp.ok:
        print 'Tenant %s deployed' % tn_name
        print 'EPG %s deployed' % EPG_name
        print '=' * 20
Exemplo n.º 8
0
def main():

    # We're going to prompt the user for a desired tenant name to build from
    # and then return the name to ensure that its correct
    tenant = ACI.Tenant(input("Enter desired tenant name: "))
    print("Tenant name is: " + tenant.name)

    # Application profile name is built from the tenant name
    # and printed to validate
    ap = ACI.AppProfile(tenant.name + "-AP", tenant)
    print("AppProfile name is: " + ap.name)

    # Two EGPs are created and tied to the previously created AP
    web_epg = ACI.EPG('web', ap)
    db_epg = ACI.EPG('db', ap)

    # A VRF is built from the tenant name and printed
    vrf = ACI.Context(tenant.name + "-CTX", tenant)
    print("VRF name is: " + vrf.name)

    # Build a bridge domain from tenant name, print
    tenant_bd = ACI.BridgeDomain(tenant.name + "-BD", tenant)
    print("BD name is: " + tenant_bd.name)

    # Finally, build the subnet from tenant name, print
    tenant_bd_subnet = ACI.Subnet(tenant.name + "-Subnet", tenant_bd)
    print("Subnet name is: " + tenant_bd_subnet.name)

    # For sake of exercise, we'll just statically assign the subnet for
    # the BD
    tenant_bd_subnet.addr = "10.1.1.1/24"

    # The BD is attached to the VRF, and options are set for flooding
    tenant_bd.add_context(vrf)
    tenant_bd.set_arp_flood('no')
    tenant_bd.set_unicast_route('yes')

    # Each of the EPGs is added to the previously created BD
    web_epg.add_bd(tenant_bd)
    db_epg.add_bd(tenant_bd)

    # The first contract, defining SQL and tied to our tenant.
    # The entry is tied to the contract and includes port and other info
    sql_contract = ACI.Contract('mssql-contract', tenant)
    sql_entry_1 = ACI.FilterEntry('ms-sql',
                         applyToFrag='no',
                         arpOpc='unspecified',
                         dFromPort='1433',
                         dToPort='1433',
                         etherT='ip',
                         prot='tcp',
                         sFromPort='1',
                         sToPort='65535',
                         tcpRules='unspecified',
                         parent=sql_contract)

    # The second contract will be for web services.  Include 80 and 443
    web_contract = ACI.Contract('web-contract', tenant)
    web_entry_1 = ACI.FilterEntry('http',
                         applyToFrag='no',
                         arpOpc='unspecified',
                         dFromPort='80',
                         dToPort='80',
                         etherT='ip',
                         prot='tcp',
                         sFromPort='1',
                         sToPort='65535',
                         tcpRules='unspecified',
                         parent=web_contract)
    web_entry_2 = ACI.FilterEntry('https',
                         applyToFrag='no',
                         arpOpc='unspecified',
                         dFromPort='443',
                         dToPort='443',
                         etherT='ip',
                         prot='tcp',
                         sFromPort='1',
                         sToPort='65535',
                         tcpRules='unspecified',
                         parent=web_contract)

    # The contracts are attached to the EPGs are providers, consumers
    db_epg.provide(sql_contract)
    web_epg.consume(sql_contract)
    web_epg.provide(web_contract)

    # Physical interfaces for attachment
    intf1 = ACI.Interface('eth', '1', '101', '1', '1')
    intf2 = ACI.Interface('eth', '1', '102', '1', '1')

    # Create a single VLAN for these interfaces.  Remember, EPGs do the allow-list
    vl10_intf1_web = ACI.L2Interface('vl10_intf1_web', 'vlan', '10')
    vl10_intf2_db = ACI.L2Interface('vl10_intf2_db', 'vlan', '10')

    # Attach the logical to physical interface config
    vl10_intf1_web.attach(intf1)
    vl10_intf2_db.attach(intf2)

    # Finally attach the EPGs to the layer-2 interface configs
    web_epg.attach(vl10_intf1_web)
    db_epg.attach(vl10_intf2_db) 

    # Now the actual "configuration push" is setup
    description = 'ACIToolkit mock full tenant configuration script'
    creds = ACI.Credentials('apic', description)
    # Adding in pieces for JSON only or delete the tenant
    creds.add_argument('--delete', action='store_true',
                    help='Delete the configuration from the APIC')
    creds.add_argument('--json', const='false', nargs='?', help='JSON output only')
    args = creds.get()
    session = ACI.Session(args.url, args.login, args.password)
    session.login()

    # Several if/else to delete the tenant or print the JSON payload
    if args.delete:
        tenant.mark_as_deleted()

    if args.json:
        print("The following JSON payload was created")
        print("URL: ", tenant.get_url())
        print(json.dumps(tenant.get_json(), indent=2))

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

        # Some error handling along the way
        if not resp.ok:
            print("%% Error: Could not push configuration to APIC")
            print(resp.text)

        else:
            print("Success")
Exemplo n.º 9
0
subnet2 = ACI.Subnet('Subnet2', bd)
subnet1.set_addr('10.20.30.1/24')
subnet2.set_addr('192.168.1.1/24')

# Add Context and Subnets to BridgeDomain
bd.add_context(context)
bd.add_subnet(subnet1)
bd.add_subnet(subnet2)

# Define three EPGs
web_epg.add_bd(bd)
app_epg.add_bd(bd)
db_epg.add_bd(bd)

# Define a contract with a single entry
contract1 = ACI.Contract('SQL-Contract', tenant)
contract1_entry1 = ACI.FilterEntry('entry1',
                                   applyToFrag='no',
                                   arpOpc='unspecified',
                                   dFromPort='3306',
                                   dToPort='3306',
                                   etherT='ip',
                                   prot='tcp',
                                   sFromPort='1',
                                   sToPort='65535',
                                   tcpRules='unspecified',
                                   parent=contract1)

# Provide the contract from one EPG and consume from the other
db_epg.provide(contract1)
app_epg.consume(contract1)
Exemplo n.º 10
0
def create_unique(session):
    # Objects for the ESXi servers in a tenant
    uni_pn = 'ESXi_PN'
    uni_bd = 'ESXi_BD'
    uni_app = 'ESXi_mgmt'
    uni_1_epg = 'Management'
    uni_2_epg = 'VMotion'
    uni_3_epg = 'Storage_acc'
    ip_segments = [
        '10.1.1.1/24',
    ]

    # Valid options for the scape are 'private', 'public', and 'shared'.  Comma seperated, and NO spaces
    subnet_scope = 'private,shared'

    # Connect to the VMM Domain
    # This must already exist.  It should have been created in this script
    vmmdomain = vmm_name

    # Setup or credentials and session
    description = ('Create EPGs for ESXi servers in a tenant.')

    # Get the virtual domain we are going to use
    vdomain = ACI.EPGDomain.get_by_name(session, vmmdomain)
    tenant = ACI.Tenant(unique_tenant)
    app = ACI.AppProfile(uni_app, tenant)

    # Create the EPGs
    u1_epg = ACI.EPG(uni_1_epg, app)
    u2_epg = ACI.EPG(uni_2_epg, app)
    u3_epg = ACI.EPG(uni_3_epg, app)

    # Create a Context and BridgeDomain
    # Place all EPGs in the Context and in the same BD
    context = ACI.Context(uni_pn, tenant)
    ubd = ACI.BridgeDomain(uni_bd, tenant)
    ubd.add_context(context)
    for subnet_ip in ip_segments:
        ran_name = [random.choice(string.hexdigits).lower() for n in xrange(6)]
        sub_name = ''.join(ran_name)
        asubnet = ACI.Subnet(sub_name, ubd)
        asubnet.set_addr(subnet_ip)
        asubnet.set_scope(subnet_scope)

    u1_epg.add_bd(ubd)
    u1_epg.add_infradomain(vdomain)
    u2_epg.add_bd(ubd)
    u2_epg.add_infradomain(vdomain)
    u3_epg.add_bd(ubd)
    ''' 
    Define contracts with a multiple entries
    '''
    contract1 = ACI.Contract('esxi_clients', tenant)
    filters = [['HTTPS', '443', 'tcp'], ['HTTP', '80', 'tcp'],
               ['SSH', '22', 'tcp']]
    for filt in filters:
        entry = ACI.FilterEntry(filt[0],
                                applyToFrag='no',
                                arpOpc='unspecified',
                                dFromPort=filt[1],
                                dToPort=filt[1],
                                etherT='ip',
                                prot=filt[2],
                                tcpRules='unspecified',
                                parent=contract1)

    # Attach the contracts
    u1_epg.provide(contract1)

    # CAUTION:  The next line will DELETE the tenant
    # tenant.mark_as_deleted()
    resp = tenant.push_to_apic(session)

    if resp.ok:
        # Uncomment the next lines if you want to see the configuration
        # print('URL: '  + str(tenant.get_url()))
        # print('JSON: ' + str(tenant.get_json()))
        return True
    else:
        return False
Exemplo n.º 11
0
def create_common(session):
    # Objects for the Vcenter servers in the common Tenant
    common_tenant = 'common'
    the_pn = 'VMware_Infra_PN'
    the_bd = 'VMware_Infra_BD'
    app_1 = 'VMware-MGMT'
    epg_1 = 'VCenter'
    app_2 = 'Shared_Services'
    epg_2 = 'Services_Servers'
    app_3 = 'IP_Storage'
    epg_3 = 'Storage_Arrays'
    ip_segments = [
        '10.1.1.1/24',
    ]

    # Connect to the VMM Domain
    # This must already exist and should have been created in this script
    vmmdomain = vmm_name

    # Setup or credentials and session
    description = (
        'Create EPGs Vcenter servers, IP Storage, and Shared Services in the common tenant.'
    )

    # Get the virtual domain we are going to use
    vdomain = ACI.EPGDomain.get_by_name(session, vmmdomain)
    tenant = ACI.Tenant(unique_tenant)
    app_1 = ACI.AppProfile(app_1, tenant)
    app_2 = ACI.AppProfile(app_2, tenant)
    app_3 = ACI.AppProfile(app_3, tenant)

    # Create the EPGs
    epg_1 = ACI.EPG(epg_1, app_1)
    epg_2 = ACI.EPG(epg_2, app_2)
    epg_3 = ACI.EPG(epg_3, app_3)

    # Create a Context and BridgeDomain
    # Place all EPGs in the Context and in the same BD
    context = ACI.Context(the_pn, tenant)
    thebd = ACI.BridgeDomain(the_bd, tenant)
    thebd.add_context(context)
    epg_1.add_bd(thebd)
    epg_1.add_infradomain(vdomain)
    epg_2.add_bd(thebd)
    epg_2.add_infradomain(vdomain)
    epg_3.add_bd(thebd)
    ''' 
    Define contracts with a multiple entries
    '''
    contract1 = ACI.Contract('vCenter_clients', tenant)
    filters = [['HTTPS', '443', 'tcp'], ['HTTP', '80', 'tcp'],
               ['SSH', '22', 'tcp']]
    for filt in filters:
        entry = ACI.FilterEntry(filt[0],
                                applyToFrag='no',
                                arpOpc='unspecified',
                                dFromPort=filt[1],
                                dToPort=filt[1],
                                etherT='ip',
                                prot=filt[2],
                                tcpRules='unspecified',
                                parent=contract1)

    # Attach the contracts
    epg_1.provide(contract1)

    # CAUTION:  The next line will DELETE the tenant
    # tenant.mark_as_deleted()
    resp = tenant.push_to_apic(session)

    if resp.ok:
        # Uncomment the next lines if you want to see the configuration
        # print('URL: '  + str(tenant.get_url()))
        # print('JSON: ' + str(tenant.get_json()))
        return True
    else:
        return False
Exemplo n.º 12
0
def main():

    #################### GET CREDENTIALS & APIC LOGIN #######################################################
    #
    ## Credentials
    #
    description = 'ACI Fabric Setup'
    creds = aci.Credentials('apic', description)
    creds.add_argument('--delete',
                       action='store_true',
                       help='Delete the configuration from the APIC')
    args = creds.get()
    #
    ## Login to the APIC
    #
    session = aci.Session(args.url, args.login, args.password)
    resp = session.login()
    if not resp.ok:
        print('%% Could not login to APIC')
    #
    #################### CREATE & PUSH ACI CONFIG ###########################################################
    #
    ## TENANT, VRF & Bridge Domains
    #
    tenant = aci.Tenant("MMTENANT0")
    tenant.descr = "Created using ACITOOLKIT"

    vrf = aci.Context("VRF-INSIDE", tenant)

    bd1 = aci.BridgeDomain("BD100", tenant)
    bd1.add_context(vrf)
    bd2 = aci.BridgeDomain("BD200", tenant)
    bd2.add_context(vrf)
    #
    ## Application Profile & EPGs
    #
    app_profile = aci.AppProfile("AP0", tenant)

    epg1 = aci.EPG("EPG100", app_profile)
    epg1.add_bd(bd1)

    epg2 = aci.EPG("EPG200", app_profile)
    epg2.add_bd(bd2)
    #
    ## Contract
    #
    # Define a contract with a single entry
    contract = aci.Contract("permit-icmp", tenant)
    entry1 = aci.FilterEntry("icmp",
                             parent=contract,
                             applyToFrag='no',
                             etherT='ip',
                             prot='icmp')

    # Apply contract in both directions

    # apply from epg1 to epg2
    epg1.provide(contract)
    epg2.consume(contract)

    # apply from epg2 to epg1
    epg1.consume(contract)
    epg2.provide(contract)
    #
    ## Push to APIC
    #
    resp = session.push_to_apic(tenant.get_url(), tenant.get_json())
    if not resp.ok:
        print('%% Error: Could not push {} configuration to APIC'.format(
            tenant.name))
        print(resp.text)
    #
    #########################################################################################################
    #
    print(" *** SCRIPT EXECUTED SUCCESSFULLY! *** ")