Add actions for ip deallocation

This commit is contained in:
jbowdre 2020-10-29 14:38:44 -05:00
parent 1be1100a6d
commit 4a47e20c72
7 changed files with 79 additions and 168 deletions

View file

@ -2,11 +2,11 @@ FROM photon:3.0-20200609
ADD target/python /ipam/python
RUN tdnf install -y python3-pip.noarch python3-devel gcc glibc-devel binutils linux-api-headers shadow && \
pip3 install --upgrade pip setuptools && \
pip3 install certifi && \
tdnf clean all && \
rm -fr /var/cache/tdnf/*
RUN tdnf install -y python3-pip.noarch python3-devel gcc glibc-devel binutils linux-api-headers shadow
RUN pip3 install --upgrade pip setuptools
RUN pip3 install certifi
RUN tdnf clean all
RUN rm -fr /var/cache/tdnf/*
RUN pip3 install -r /ipam/python/allocate_ip/requirements.txt --target=/ipam/python/allocate_ip
RUN pip3 install -r /ipam/python/deallocate_ip/requirements.txt --target=/ipam/python/deallocate_ip

View file

@ -1,2 +1,4 @@
requests==2.21.0
OrionSDK
orionsdk
ipaddress
datetime

View file

@ -12,64 +12,11 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
import requests
from vra_ipam_utils.ipam import IPAM
import logging
from OrionSDK import SWisClient
from orionsdk import SwisClient
from datetime import datetime
import ipaddress
import socket
"""
Example payload
"inputs": {
"resourceInfo": {
"id": "11f912e71454a075574a728848458",
"name": "external-ipam-it-mcm-323412",
"description": "test",
"type": "VM",
"owner": "mdzhigarov@vmware.com",
"orgId": "ce811934-ea1a-4f53-b6ec-465e6ca7d126",
"properties": {
"osType": "WINDOWS",
"vcUuid": "ff257ed9-070b-45eb-b2e7-d63926d5bdd7",
"__moref": "VirtualMachine:vm-288560",
"memoryGB": "4",
"datacenter": "Datacenter:datacenter-2",
"provisionGB": "1",
"__dcSelfLink": "/resources/groups/b28c7b8de065f07558b1612fce028",
"softwareName": "Microsoft Windows XP Professional (32-bit)",
"__computeType": "VirtualMachine",
"__hasSnapshot": "false",
"__placementLink": "/resources/compute/9bdc98681fb8b27557252188607b8",
"__computeHostLink": "/resources/compute/9bdc98681fb8b27557252188607b8"
}
},
"ipAllocations": [
{
"id": "111bb2f0-02fd-4983-94d2-8ac11768150f",
"ipRangeIds": [
"network/ZG5zLm5ldHdvcmskMTAuMjMuMTE3LjAvMjQvMA:10.23.117.0/24/default"
],
"nicIndex": "0",
"isPrimary": "true",
"size": "1",
"properties": {
"__moref": "DistributedVirtualPortgroup:dvportgroup-307087",
"__dvsUuid": "0c 8c 0b 50 46 b6 1c f2-e8 63 f4 24 24 d7 24 6c",
"__dcSelfLink": "/resources/groups/abe46b8cfa663a7558b28a6ffe088",
"__computeType": "DistributedVirtualPortgroup",
"__portgroupKey": "dvportgroup-307087"
}
}
],
"endpoint": {
"id": "f097759d8736675585c4c5d272cd",
"endpointProperties": {
"hostName": "sampleipam.sof-mbu.eng.vmware.com",
"projectId": "111bb2f0-02fd-4983-94d2-8ac11768150f",
"providerId": "d8a5e3f2-d839-4365-af5b-f48de588fdc1",
"certificate": "-----BEGIN CERTIFICATE-----\nMIID0jCCArqgAwIBAgIQQaJF55UCb58f9KgQLD/QgTANBgkqhkiG9w0BAQUFADCB\niTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1\nbm55dmFsZTERMA8GA1UEChMISW5mb2Jsb3gxFDASBgNVBAsTC0VuZ2luZWVyaW5n\nMSgwJgYDVQQDEx9pbmZvYmxveC5zb2YtbWJ1LmVuZy52bXdhcmUuY29tMB4XDTE5\nMDEyOTEzMDExMloXDTIwMDEyOTEzMDExMlowgYkxCzAJBgNVBAYTAlVTMRMwEQYD\nVQQIEwpDYWxpZm9ybmlhMRIwEAYDVQQHEwlTdW5ueXZhbGUxETAPBgNVBAoTCElu\nZm9ibG94MRQwEgYDVQQLEwtFbmdpbmVlcmluZzEoMCYGA1UEAxMfaW5mb2Jsb3gu\nc29mLW1idS5lbmcudm13YXJlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\nAQoCggEBAMMLNTqbAri6rt/H8iC4UgRdN0qj+wk0R2blmD9h1BiZJTeQk1r9i2rz\nzUOZHvE8Bld8m8xJ+nysWHaoFFGTX8bOd/p20oJBGbCLqXtoLMMBGAlP7nzWGBXH\nBYUS7kMv/CG+PSX0uuB0pRbhwOFq8Y69m4HRnn2X0WJGuu+v0FmRK/1m/kCacHga\nMBKaIgbwN72rW1t/MK0ijogmLR1ASY4FlMn7OBHIEUzO+dWFBh+gPDjoBECTTH8W\n5AK9TnYdxwAtJRYWmnVqtLoT3bImtSfI4YLUtpr9r13Kv5FkYVbXov1KBrQPbYyp\n72uT2ZgDJT4YUuWyKpMppgw1VcG3MosCAwEAAaM0MDIwMAYDVR0RBCkwJ4cEChda\nCoIfaW5mb2Jsb3guc29mLW1idS5lbmcudm13YXJlLmNvbTANBgkqhkiG9w0BAQUF\nAAOCAQEAXFPIh00VI55Sdfx+czbBb4rJz3c1xgN7pbV46K0nGI8S6ufAQPgLvZJ6\ng2T/mpo0FTuWCz1IE9PC28276vwv+xJZQwQyoUq4lhT6At84NWN+ZdLEe+aBAq+Y\nxUcIWzcKv8WdnlS5DRQxnw6pQCBdisnaFoEIzngQV8oYeIemW4Hcmb//yeykbZKJ\n0GTtK5Pud+kCkYmMHpmhH21q+3aRIcdzOYIoXhdzmIKG0Och97HthqpvRfOeWQ/A\nPDbxqQ2R/3D0gt9jWPCG7c0lB8Ynl24jLBB0RhY6mBrYpFbtXBQSEciUDRJVB2zL\nV8nJiMdhj+Q+ZmtSwhNRvi2qvWAUJQ==\n-----END CERTIFICATE-----\n"
},
"authCredentialsLink": "/core/auth/credentials/13c9cbade08950755898c4b89c4a0"
}
}
"""
def handler(context, inputs):
ipam = IPAM(context, inputs)
@ -78,10 +25,14 @@ def handler(context, inputs):
return ipam.allocate_ip()
def do_allocate_ip(self, auth_credentials, cert):
# Your implemention goes here
username = auth_credentials["privateKeyId"]
password = auth_credentials["privateKey"]
hostname = self.inputs['endpoint']['endpointProperties']['hostName']
global swis
swis = SwisClient(hostname, username, password)
requests.packages.urllib3.disable_warnings()
allocation_result = []
try:
resource = self.inputs["resourceInfo"]
@ -117,28 +68,62 @@ def allocate(resource, allocation, context, endpoint):
def allocate_in_range(range_id, resource, allocation, context, endpoint):
if int(allocation['size']) == 1:
vmName = resource['name']
owner = resource['owner']
## Plug your implementation here to allocate an ip address
## ...
## Allocation successful
logging.info(f"Grabbing details about IP range ID {range_id}...")
qNetwork = swis.query(f"SELECT DISTINCT Address, CIDR FROM IPAM.GroupNode WHERE GroupTypeText LIKE 'Subnet' AND GroupID = {range_id}")
network = ipaddress.ip_network(f"{qNetwork['results'][0]['Address']}/{qNetwork['results'][0]['CIDR']}")
maxOrdinal = network.num_addresses -5
result = {
"ipAllocationId": allocation["id"],
"ipRangeId": range_id,
"ipVersion": "IPv4"
}
logging.info(f"Grabbing next available IPs...")
qAddresses = swis.query(f"SELECT TOP 5 IpNodeId, IpAddress FROM IPAM.IPNode WHERE SubnetId = {range_id} AND IPOrdinal > 9 AND IPOrdinal < {maxOrdinal} AND Status = 2 AND LastSync IS NULL")
for address in qAddresses['results']:
ipAddress = address['IpAddress']
nodeId = address['IpNodeId']
if check_dns(ipAddress) == True:
logging.info(f"Reserving IP address {ipAddress}...")
uri = f'swis://localhost/Orion/IPAM.IPNode/IpNodeId={nodeId}'
swis.invoke("IPAM.SubnetManagement", "ChangeIPStatus", ipAddress, "Reserved")
swis.update(uri, Comments=f"Reserved by {owner} at {datetime.now()}.", DnsBackward=vmName)
logging.info(f"Successfully reserved {ipAddress} for {vmName}.")
result = {
"ipAllocationId": allocation['id'],
"ipRangeId": range_id,
"ipVersion": f"IPv{network.version}",
"ipAddresses": [ipAddress]
}
break
return result
result["ipAddresses"] = ["10.23.117.5"]
result["properties"] = {"customPropertyKey1": "customPropertyValue1"}
return result
else:
# TODO: allocate continuous block of ips
pass
raise Exception("Not implemented")
## Rollback any previously allocated addresses in case this allocation request contains multiple ones and failed in the middle
def rollback(allocation_result):
for allocation in reversed(allocation_result):
logging.info(f"Rolling back allocation {str(allocation)}")
ipAddresses = allocation.get("ipAddresses", None)
## release the address
for ipAddress in ipAddresses:
swis.invoke("IPAM.SubnetManagement", "ChangeIPStatus", ipAddress, "Available")
return
def check_dns(ipAddress):
logging.info(f"Checking DNS for {ipAddress}...")
try:
socket.gethostbyaddr(ipAddress)
except Exception as e:
if '[Errno 1]' in str(e):
# No PTR record for that IP
logging.info(f"Great news: No DNS record found.")
return True
else:
logging.info(f"Encountered an error: {e}.")
return False
else:
# There might be a conflict
return False
logging.info(f"Uh-oh, found a conflicting DNS record.")

View file

@ -1 +1,2 @@
requests==2.21.0
orionsdk

View file

@ -12,52 +12,8 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
import requests
from vra_ipam_utils.ipam import IPAM
import logging
from orionsdk import SwisClient
"""
Example payload:
"inputs": {
"resourceInfo": {
"id": "11f912e71454a075574a728848458",
"name": "external-ipam-it-mcm-323412",
"description": "test",
"type": "VM",
"owner": "mdzhigarov@vmware.com",
"orgId": "ce811934-ea1a-4f53-b6ec-465e6ca7d126",
"properties": {
"osType": "WINDOWS",
"vcUuid": "ff257ed9-070b-45eb-b2e7-d63926d5bdd7",
"__moref": "VirtualMachine:vm-288560",
"memoryGB": "4",
"datacenter": "Datacenter:datacenter-2",
"provisionGB": "1",
"__dcSelfLink": "/resources/groups/b28c7b8de065f07558b1612fce028",
"softwareName": "Microsoft Windows XP Professional (32-bit)",
"__computeType": "VirtualMachine",
"__hasSnapshot": "false",
"__placementLink": "/resources/compute/9bdc98681fb8b27557252188607b8",
"__computeHostLink": "/resources/compute/9bdc98681fb8b27557252188607b8"
}
},
"ipDeallocations": [
{
"id": "111bb2f0-02fd-4983-94d2-8ac11768150f",
"ipRangeId": "network/ZG5zLm5ldHdvcmskMTAuMjMuMTE3LjAvMjQvMA:10.23.117.0/24/default",
"ipAddress": "10.23.117.5"
}
],
"endpoint": {
"id": "f097759d8736675585c4c5d272cd",
"endpointProperties": {
"hostName": "sampleipam.sof-mbu.eng.vmware.com",
"projectId": "111bb2f0-02fd-4983-94d2-8ac11768150f",
"providerId": "d8a5e3f2-d839-4365-af5b-f48de588fdc1",
"certificate": "-----BEGIN CERTIFICATE-----\nMIID0jCCArqgAwIBAgIQQaJF55UCb58f9KgQLD/QgTANBgkqhkiG9w0BAQUFADCB\niTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1\nbm55dmFsZTERMA8GA1UEChMISW5mb2Jsb3gxFDASBgNVBAsTC0VuZ2luZWVyaW5n\nMSgwJgYDVQQDEx9pbmZvYmxveC5zb2YtbWJ1LmVuZy52bXdhcmUuY29tMB4XDTE5\nMDEyOTEzMDExMloXDTIwMDEyOTEzMDExMlowgYkxCzAJBgNVBAYTAlVTMRMwEQYD\nVQQIEwpDYWxpZm9ybmlhMRIwEAYDVQQHEwlTdW5ueXZhbGUxETAPBgNVBAoTCElu\nZm9ibG94MRQwEgYDVQQLEwtFbmdpbmVlcmluZzEoMCYGA1UEAxMfaW5mb2Jsb3gu\nc29mLW1idS5lbmcudm13YXJlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\nAQoCggEBAMMLNTqbAri6rt/H8iC4UgRdN0qj+wk0R2blmD9h1BiZJTeQk1r9i2rz\nzUOZHvE8Bld8m8xJ+nysWHaoFFGTX8bOd/p20oJBGbCLqXtoLMMBGAlP7nzWGBXH\nBYUS7kMv/CG+PSX0uuB0pRbhwOFq8Y69m4HRnn2X0WJGuu+v0FmRK/1m/kCacHga\nMBKaIgbwN72rW1t/MK0ijogmLR1ASY4FlMn7OBHIEUzO+dWFBh+gPDjoBECTTH8W\n5AK9TnYdxwAtJRYWmnVqtLoT3bImtSfI4YLUtpr9r13Kv5FkYVbXov1KBrQPbYyp\n72uT2ZgDJT4YUuWyKpMppgw1VcG3MosCAwEAAaM0MDIwMAYDVR0RBCkwJ4cEChda\nCoIfaW5mb2Jsb3guc29mLW1idS5lbmcudm13YXJlLmNvbTANBgkqhkiG9w0BAQUF\nAAOCAQEAXFPIh00VI55Sdfx+czbBb4rJz3c1xgN7pbV46K0nGI8S6ufAQPgLvZJ6\ng2T/mpo0FTuWCz1IE9PC28276vwv+xJZQwQyoUq4lhT6At84NWN+ZdLEe+aBAq+Y\nxUcIWzcKv8WdnlS5DRQxnw6pQCBdisnaFoEIzngQV8oYeIemW4Hcmb//yeykbZKJ\n0GTtK5Pud+kCkYmMHpmhH21q+3aRIcdzOYIoXhdzmIKG0Och97HthqpvRfOeWQ/A\nPDbxqQ2R/3D0gt9jWPCG7c0lB8Ynl24jLBB0RhY6mBrYpFbtXBQSEciUDRJVB2zL\nV8nJiMdhj+Q+ZmtSwhNRvi2qvWAUJQ==\n-----END CERTIFICATE-----\n"
},
"authCredentialsLink": "/core/auth/credentials/13c9cbade08950755898c4b89c4a0"
}
}
"""
def handler(context, inputs):
ipam = IPAM(context, inputs)
@ -66,10 +22,14 @@ def handler(context, inputs):
return ipam.deallocate_ip()
def do_deallocate_ip(self, auth_credentials, cert):
# Your implemention goes here
username = auth_credentials["privateKeyId"]
password = auth_credentials["privateKey"]
hostname = self.inputs['endpoint']['endpointProperties']['hostName']
global swis
swis = SwisClient(hostname, username, password)
requests.packages.urllib3.disable_warnings()
deallocation_result = []
for deallocation in self.inputs["ipDeallocations"]:
deallocation_result.append(deallocate(self.inputs["resourceInfo"], deallocation))
@ -85,11 +45,7 @@ def deallocate(resource, deallocation):
resource_id = resource["id"]
logging.info(f"Deallocating ip {ip} from range {ip_range_id}")
## Plug your implementation here to deallocate an already allocated ip address
## ...
## Deallocation successful
swis.invoke("IPAM.SubnetManagement", "ChangeIPStatus", ip, "Available")
return {
"ipDeallocationId": deallocation["id"],
"message": "Success"

View file

@ -15,24 +15,6 @@ import logging
from orionsdk import SwisClient
import ipaddress
'''
Example payload:
"inputs": {
"endpoint": {
"id": "f097759d8736675585c4c5d272cd",
"authCredentialsLink": "/core/auth/credentials/13c9cbade08950755898c4b89c4a0",
"endpointProperties": {
"hostName": "sampleipam.sof-mbu.eng.vmware.com",
"certificate": "-----BEGIN CERTIFICATE-----\nMIID0jCCArqgAwIBAgIQQaJF55UCb58f9KgQLD/QgTANBgkqhkiG9w0BAQUFADCB\niTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1\nbm55dmFsZTERMA8GA1UEChMISW5mb2Jsb3gxFDASBgNVBAsTC0VuZ2luZWVyaW5n\nMSgwJgYDVQQDEx9pbmZvYmxveC5zb2YtbWJ1LmVuZy52bXdhcmUuY29tMB4XDTE5\nMDEyOTEzMDExMloXDTIwMDEyOTEzMDExMlowgYkxCzAJBgNVBAYTAlVTMRMwEQYD\nVQQIEwpDYWxpZm9ybmlhMRIwEAYDVQQHEwlTdW5ueXZhbGUxETAPBgNVBAoTCElu\nZm9ibG94MRQwEgYDVQQLEwtFbmdpbmVlcmluZzEoMCYGA1UEAxMfaW5mb2Jsb3gu\nc29mLW1idS5lbmcudm13YXJlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\nAQoCggEBAMMLNTqbAri6rt/H8iC4UgRdN0qj+wk0R2blmD9h1BiZJTeQk1r9i2rz\nzUOZHvE8Bld8m8xJ+nysWHaoFFGTX8bOd/p20oJBGbCLqXtoLMMBGAlP7nzWGBXH\nBYUS7kMv/CG+PSX0uuB0pRbhwOFq8Y69m4HRnn2X0WJGuu+v0FmRK/1m/kCacHga\nMBKaIgbwN72rW1t/MK0ijogmLR1ASY4FlMn7OBHIEUzO+dWFBh+gPDjoBECTTH8W\n5AK9TnYdxwAtJRYWmnVqtLoT3bImtSfI4YLUtpr9r13Kv5FkYVbXov1KBrQPbYyp\n72uT2ZgDJT4YUuWyKpMppgw1VcG3MosCAwEAAaM0MDIwMAYDVR0RBCkwJ4cEChda\nCoIfaW5mb2Jsb3guc29mLW1idS5lbmcudm13YXJlLmNvbTANBgkqhkiG9w0BAQUF\nAAOCAQEAXFPIh00VI55Sdfx+czbBb4rJz3c1xgN7pbV46K0nGI8S6ufAQPgLvZJ6\ng2T/mpo0FTuWCz1IE9PC28276vwv+xJZQwQyoUq4lhT6At84NWN+ZdLEe+aBAq+Y\nxUcIWzcKv8WdnlS5DRQxnw6pQCBdisnaFoEIzngQV8oYeIemW4Hcmb//yeykbZKJ\n0GTtK5Pud+kCkYmMHpmhH21q+3aRIcdzOYIoXhdzmIKG0Och97HthqpvRfOeWQ/A\nPDbxqQ2R/3D0gt9jWPCG7c0lB8Ynl24jLBB0RhY6mBrYpFbtXBQSEciUDRJVB2zL\nV8nJiMdhj+Q+ZmtSwhNRvi2qvWAUJQ==\n-----END CERTIFICATE-----\n"
}
},
"pagingAndSorting": {
"maxResults": 1000,
"pageToken": "789c55905d6e02310c84df7d91452a456481168ec04b55950344f9db55dadd384abc056e5f3b42adfa12299f279ec9ac7c5670e9b0045a4ad2430c93af7a465f3bc83d4f9e3aa8976e6681ce660c827770de2aa1a68c72dfc3cae74393999b2e4df302e72691373aa60199bd827398efac18810f87a952591c61817c849513999df0b6c11436d6d400effcfacc14f2099cd6768913c5a435a0fd0c8e20ab2dbcd147564a2228c93b60b99ae2d94efde6ac640a09d9331130c539367078c41c915067ac9122268dc350439bf3379e9bc01b32025e9bd111aa65c829e89e83f0135ba740572c5f525c73f95faa608e39e55e62c6fcbd37de9775b891212a758d59bceb7a0eb30d7c7f6cd35c1399984291053b30f29fc5feed6cedf7adfe21962ab17b8ebde5089b1fec0d97d7-e5c4e5a1d726f600c22ebfd9f186148a1449755fd79a69ceabfe2aa"
}
}
'''
def handler(context, inputs):
ipam = IPAM(context, inputs)

View file

@ -15,19 +15,6 @@ from vra_ipam_utils.exceptions import InvalidCertificateException
import logging
from orionsdk import SwisClient
'''
Example payload:
"inputs": {
"authCredentialsLink": "/core/auth/credentials/13c9cbade08950755898c4b89c4a0",
"endpointProperties": {
"hostName": "sampleipam.sof-mbu.eng.vmware.com"
}
}
'''
def handler(context, inputs):
ipam = IPAM(context, inputs)
@ -36,8 +23,6 @@ def handler(context, inputs):
return ipam.validate_endpoint()
def do_validate_endpoint(self, auth_credentials, cert):
# Your implemention goes here
username = auth_credentials["privateKeyId"]
password = auth_credentials["privateKey"]
hostname = self.inputs["endpointProperties"]["hostName"]