blob: d2d1f97d31f9a7e4f9092444a115a3b0aa1710ae [file] [log] [blame]
import os
import requests
import socket
import sys
import base64
from django.db.models import F, Q
from xos.config import Config
from synchronizers.base.syncstep import SyncStep
from synchronizers.base.ansible import run_template_ssh
from core.models import Service
from services.cord.models import VCPEService, VSGTenant, VBNGTenant, VBNGService
from services.hpc.models import HpcService, CDNPrefix
from xos.logger import Logger, logging
# VBNG_API = "http://10.0.3.136:8181/onos/virtualbng/privateip/"
# hpclibrary will be in steps/..
parentdir = os.path.join(os.path.dirname(__file__),"..")
sys.path.insert(0,parentdir)
logger = Logger(level=logging.INFO)
class SyncVBNGTenant(SyncStep):
provides=[VSGTenant]
observes=VSGTenant
requested_interval=0
def __init__(self, **args):
SyncStep.__init__(self, **args)
def fetch_pending(self, deleted):
if (not deleted):
objs = VBNGTenant.get_tenant_objects().filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False))
else:
objs = VBNGTenant.get_deleted_tenant_objects()
return objs
def defer_sync(self, o, reason):
logger.info("defer object %s due to %s" % (str(o), reason))
raise Exception("defer object %s due to %s" % (str(o), reason))
def get_vbng_service(self, o):
if not o.provider_service:
raise Exception("vBNG tenant %s has no provider_service" % str(o.id))
services = VBNGService.get_service_objects().filter(id = o.provider_service.id)
if not services:
raise Exception("vBNG tenant %s is associated with the wrong kind of provider_service" % str(o.id))
return services[0]
def get_vbng_url(self, o):
service = self.get_vbng_service(o)
# if the service object specifies a vbng_url, then use it
if service.vbng_url:
return service.vbng_url
# otherwise, see if the service has tenancy in ONOS
for tenant in service.subscribed_tenants.all():
if tenant.provider_service and tenant.provider_service.kind == "onos":
onos_service = tenant.provider_service
if not onos_service.slices.exists():
raise Exception("vBNG service is linked to an ONOSApp, but the App's Service has no slices")
onos_slice = onos_service.slices.all()[0]
if not onos_slice.instances.exists():
raise Exception("vBNG service is linked to an ONOSApp, but the App's Service's Slice has no instances")
instance = onos_slice.instances.all()[0]
#onos_app = ONOSApp.objects.filter(id = tenant.id)
#instance = onos_app.instance
#if not instance:
# raise Exception("ONOSApp has no instance")
if not instance.instance_name:
raise Exception("vBNG service is linked to an ONOSApp, but the App's Service's Slice's first instance is not instantiated")
ip = instance.get_network_ip("nat")
if not ip:
raise Exception("vBNG service is linked to an ONOSApp, but the App's Service's Slice's first instance does not have an ip")
logger.info("Using ip %s from ONOS Instance %s" % (ip, instance))
return "http://%s:8181/onos/virtualbng/" % ip
raise Exception("vBNG service does not have vbng_url set, and is not linked to an ONOSApp")
def get_private_interface(self, o):
vcpes = VSGTenant.get_tenant_objects().all()
vcpes = [x for x in vcpes if (x.vbng is not None) and (x.vbng.id == o.id)]
if not vcpes:
raise Exception("No vCPE tenant is associated with vBNG %s" % str(o.id))
if len(vcpes)>1:
raise Exception("More than one vCPE tenant is associated with vBNG %s" % str(o.id))
vcpe = vcpes[0]
instance = vcpe.instance
if not instance:
raise Exception("No instance associated with vBNG %s" % str(o.id))
if not vcpe.wan_ip:
self.defer_sync(o, "does not have a WAN IP yet")
if not vcpe.wan_container_mac:
# this should never happen; container MAC is computed from WAN IP
self.defer_sync(o, "does not have a WAN container MAC yet")
return (vcpe.wan_ip, vcpe.wan_container_mac, vcpe.instance.node.name)
def sync_record(self, o):
logger.info("sync'ing VBNGTenant %s" % str(o))
if not o.routeable_subnet:
(private_ip, private_mac, private_hostname) = self.get_private_interface(o)
logger.info("contacting vBNG service to request mapping for private ip %s mac %s host %s" % (private_ip, private_mac, private_hostname) )
url = self.get_vbng_url(o) + "privateip/%s/%s/%s" % (private_ip, private_mac, private_hostname)
logger.info( "vbng url: %s" % url )
r = requests.post(url )
if (r.status_code != 200):
raise Exception("Received error from bng service (%d)" % r.status_code)
logger.info("received public IP %s from private IP %s" % (r.text, private_ip))
if r.text == "0":
raise Exception("VBNG service failed to return a routeable_subnet (probably ran out)")
o.routeable_subnet = r.text
o.mapped_ip = private_ip
o.mapped_mac = private_mac
o.mapped_hostname = private_hostname
o.save()
def delete_record(self, o):
logger.info("deleting VBNGTenant %s" % str(o))
if o.mapped_ip:
private_ip = o.mapped_ip
logger.info("contacting vBNG service to delete private ip %s" % private_ip)
r = requests.delete(self.get_vbng_url(o) + "privateip/%s" % private_ip, )
if (r.status_code != 200):
raise Exception("Received error from bng service (%d)" % r.status_code)