Пример #1
0
class DemoScript(Script):
    name = "Script Demo"
    description = "A quick demonstration of the available field types"

    my_string1 = StringVar(
        description="Input a string between 3 and 10 characters",
        min_length=3,
        max_length=10)
    my_string2 = StringVar(
        description=
        "This field enforces a regex: three letters followed by three numbers",
        regex=r'[a-z]{3}\d{3}')
    my_number = IntegerVar(
        description="Pick a number between 1 and 255 (inclusive)",
        min_value=1,
        max_value=255)
    my_boolean = BooleanVar(
        description="Use the checkbox to toggle true/false")
    my_object = ObjectVar(description="Select a NetBox site",
                          queryset=Site.objects.all())

    def run(self, data):

        self.log_info("Your string was {}".format(data['my_string1']))
        self.log_info("Your second string was {}".format(data['my_string2']))
        self.log_info("Your number was {}".format(data['my_number']))
        if data['my_boolean']:
            self.log_info("You ticked the checkbox")
        else:
            self.log_info("You did not tick the checkbox")
        self.log_info("You chose the sites {}".format(data['my_object']))

        return "Here's some output"
Пример #2
0
    class TestScript(Script):
        class Meta:
            name = "Test script"

        var1 = StringVar()
        var2 = IntegerVar()
        var3 = BooleanVar()

        def run(self, data, commit=True):

            self.log_info(data['var1'])
            self.log_success(data['var2'])
            self.log_failure(data['var3'])

            return 'Script complete'
class New(Script):
    class Meta:
        name = "Create FTTB CPE w/ automatic uplink selection and monitoring"
        description = "Generate standard CPE router configuration \
                       and configure uplink switch and linkage"

        field_order = [
            'business_name', 'asset_tag', 'uplink_site', 'skip_zabbix',
            'skip_uplink_port', 'confirmation_email', 'comments', 'rack_mount'
        ]

    # ##################Check to make sure you have these defined##############
    RACK_MOUNT_ID = DeviceType.objects.get(model="RB2011-RM").id
    WALL_MOUNT_ID = DeviceType.objects.get(model="RB2011").id
    SITE_ID = Site.objects.get(name="Customer Premise").id
    DEVICE_ROLE_ID = DeviceRole.objects.get(name="CPE").id
    AGG_ROLE_ID = DeviceRole.objects.get(name="Aggregation").id
    PLATFORM_ID = Platform.objects.get(name="RouterOS").id
    CHOICES = ((RACK_MOUNT_ID, "Rack Mount"), (WALL_MOUNT_ID, "Wall Mount"))
    INET_VLAN = VLAN.objects.get(vid=900)
    MGMT_VLAN = VLAN.objects.get(vid=107)
    #SITES = Site.objects.filter(region_id=1)
    REGION = 1
    ZAPI = ZabbixAPI(
        url='http://zabbix-web-apache-mysql:8080/api_jsonrpc.php/',
        user='******',
        password='******')
    SNMP_COMMUNITY = "got"
    # ##################END###################

    rack_mount = ChoiceVar(choices=((True, "Rack Mount"), (False,
                                                           "Wall Mount")))
    business_name = StringVar(label="Business Name")
    asset_tag = StringVar(label="Asset Tag", required=False)
    hardware_choice = ChoiceVar(choices=CHOICES)
    comments = TextVar(label="Comments", required=False)
    uplink_site = ObjectVar(model=Site, query_params={'region_id': REGION})
    skip_zabbix = BooleanVar(label="Disable Zabbix configuration")
    skip_uplink_port = BooleanVar(label="Disable upstream port selection")
    confirmation_email = BooleanVar(label="Send Confirmation Email")

    def run(self, data, commit):
        # Create the device
        device = Device(name=data['business_name'],
                        device_role_id=self.DEVICE_ROLE_ID,
                        device_type_id=data["hardware_choice"],
                        platform_id=self.PLATFORM_ID,
                        site_id=self.SITE_ID)
        device.save()

        interfaces = Interface.objects.filter(device_id=device.id)
        enabled_interfaces = []
        mgmt_intf = interfaces.get(name="b107")
        enabled_interfaces.append(mgmt_intf)
        uplk_intf = interfaces.get(name="ether10")
        enabled_interfaces.append(uplk_intf)
        uplk_intf.mode = "tagged"
        uplk_intf.tagged_vlans.set([self.INET_VLAN, self.MGMT_VLAN])
        uplk_intf.description = "Uplink"
        uplk_intf.save()
        inet_intf = interfaces.get(name="ether1")
        enabled_interfaces.append(inet_intf)
        inet_intf.description = "Internet"
        inet_intf.mode = "access"
        inet_intf.untagged_vlan = self.INET_VLAN
        inet_intf.save()
        mgmt_intf.save()
        for intf in interfaces:
            intf.enabled = False
            intf.save()
        for intf in enabled_interfaces:
            intf.enabled = True
            intf.mtu = 1500
            intf.save()
        available_ip = Prefix.objects.get(
            vlan=self.MGMT_VLAN).get_first_available_ip()
        ip = IPAddress(
            address=available_ip,
            assigned_object_type=ContentType.objects.get_for_model(Interface),
            assigned_object_id=mgmt_intf.id)
        ip.save()
        device.primary_ip4_id = ip.id
        device.primary_ip_id = ip.id
        device.comments = data['comments']
        device.save()

        # ############
        if (not data["skip_zabbix"] and commit):

            # Post to Zabbix API to create host in mikrotik group and ICMP
            # template
            try:
                hostid = self.ZAPI.host.create(
                    host=data["business_name"],
                    interfaces=dict(type=2,
                                    main=1,
                                    useip=1,
                                    ip=available_ip.replace("/24", ""),
                                    port=161,
                                    dns="",
                                    details=dict(
                                        version="1",
                                        bulk="0",
                                        community=self.SNMP_COMMUNITY)),
                    groups=dict(groupid=15),
                    templates=dict(templateid=10186))
                self.log_info("zabbix configured successfully")
            except Exception as e:
                self.log_info("failed to configure zabbix {0}".format(e))

        if (not data["skip_uplink_port"] and commit):
            try:
                agg_switches = Device.objects.filter(
                    site=data["uplink_site"],
                    device_role_id=self.AGG_ROLE_ID,
                    status="active")
                selected_interface = ""
                for agg_switch in agg_switches:
                    interfaces = Interface.objects.filter(
                        device_id=agg_switch.id)
                    for interface in interfaces:
                        if (interface.connection_status is not True
                                and interface.enabled is True
                                and interface.description == ''
                                and interface.type == '1000base-x-sfp'):
                            selected_interface = interface
                            break
                    if selected_interface != "":
                        selected_interface.enabled = True
                        selected_interface.description = device.name
                        selected_interface.mode = "tagged"
                        selected_interface.tagged_vlans.set(
                            [self.INET_VLAN, self.MGMT_VLAN])
                        selected_interface.save()
                        cable = Cable(
                            termination_a=uplk_intf,
                            termination_b=selected_interface,
                        )
                        cable.save()
                        self.log_info(
                            "uplink switch chosen. Port {0} on {1}".format(
                                selected_interface.name, agg_switch.name))
                        break
                if selected_interface == "":
                    self.log_failure("No available aggregate port found. \
                        No aggregate port assigned.")

            except BaseException:
                self.log("failed to document uplink switch")

        self.log_success("Created {0}".format(device.name))
Пример #4
0
class NewVM(Script):
    class Meta:
        name = "New VM"
        description = "Create a new VM"
        field_order = [
            'vm_name',
            'dns_name',
            'primary_ip4',
            'primary_ip6',  #'vrf',
            'role',
            'status',
            'cluster',  #'tenant',
            'platform',
            'interface_name',
            'mac_address',
            'vcpus',
            'memory',
            'disk',
            'comments'
        ]

    vm_name = StringVar(label="VM name")
    dns_name = StringVar(label="DNS name", required=False)
    primary_ip4 = IPAddressWithMaskVar(label="IPv4 address")
    primary_ip6 = IPAddressWithMaskVar(label="IPv6 address", required=False)
    #vrf = ObjectVar(VRF.objects, required=False)
    role = ObjectVar(DeviceRole.objects.filter(vm_role=True), required=False)
    status = ChoiceVar(VirtualMachineStatusChoices,
                       default=VirtualMachineStatusChoices.STATUS_ACTIVE)
    cluster = ObjectVar(Cluster.objects)
    #tenant = ObjectVar(Tenant.objects, required=False)
    platform = ObjectVar(Platform.objects, required=False)
    interface_name = StringVar(default="eth0")
    mac_address = StringVar(label="MAC address", required=False)
    vcpus = IntegerVar(label="VCPUs", required=False)
    memory = IntegerVar(label="Memory (MB)", required=False)
    disk = IntegerVar(label="Disk (GB)", required=False)
    comments = TextVar(label="Comments", required=False)

    def run(self, data):
        vm = VirtualMachine(
            name=data["vm_name"],
            role=data["role"],
            status=data["status"],
            cluster=data["cluster"],
            platform=data["platform"],
            vcpus=data["vcpus"],
            memory=data["memory"],
            disk=data["disk"],
            comments=data["comments"],
            tenant=data.get("tenant"),
        )
        vm.save()

        interface = Interface(
            name=data["interface_name"],
            type=InterfaceTypeChoices.TYPE_VIRTUAL,
            mac_address=data["mac_address"],
            virtual_machine=vm,
        )
        interface.save()

        def add_addr(addr, expect_family):
            if not addr:
                return
            if addr.version != expect_family:
                raise RuntimeError("Wrong family for %r" % a)
            try:
                a = IPAddress.objects.get(
                    address=addr,
                    vrf=data.get("vrf"),
                )
                result = "Assigned"
            except ObjectDoesNotExist:
                a = IPAddress(
                    address=addr,
                    vrf=data.get("vrf"),
                )
                result = "Created"
            a.status = IPAddressStatusChoices.STATUS_ACTIVE
            a.dns_name = data["dns_name"]
            if a.interface:
                raise RuntimeError("Address %s is already assigned" % addr)
            a.interface = interface
            a.tenant = data.get("tenant")
            a.save()
            self.log_info("%s IP address %s %s" %
                          (result, a.address, a.vrf or ""))
            setattr(vm, "primary_ip%d" % a.family, a)

        add_addr(data["primary_ip4"], 4)
        add_addr(data["primary_ip6"], 6)
        vm.save()
        self.log_success("Created VM %s" % vm.name)
class InterfaceUpdate(Script):
    """Script that can be used to auto generate interfaces from devices using NAPALM

    Args:
        Script (:obj:`extras.script.Script`): Netbox Script object that is needed for a class to be recognized as one
    """

    class Meta:
        """Special class that is used for defining script information"""

        name = "Interface update"
        description = "Script that updates interfaces for device names provided"
        commit_default = False

    device_name = StringVar(
        label="Devices regex",
        default="(r6|v22)-leaf((1\d*|[2-9])|1)",
        description="Regex that will be used to select devices to update interfaces",
    )
    ignore_interfaces = StringVar(
        label="Interfaces to ignore regex",
        default="Vlan.*",
        description="Regex that will ignore interfaces matching it (Leave blank to not ignore any)",
    )

    def run(self, data, commit: bool):
        """The main method of the script that will be run when pressing the Run Script button

        1. Grabs the data from Netbox about devices containing the devices by regex input by the user
        2. Loops through the devices, grabs their current Netbox interfaces and then makes a NAPALM call to the device
        3. Loops through NAPALM interfaces, while ignoring the ones matching the user supplied regex
        4. If a mac_address is any kind of empty or null, it makes sure to set it to python None
        5. Using get_or_create, grabs or creates the interface from Netbox while filtering by the specific NAPALM interface the loop is currently on
        6. Notifies user if a interface was created and if it wasn't checks if the description in Netbox matches NAPALM description
        7. Updates description if neccessary, notifying user of it.

        Args:
            data (dict): a dict that has the variables for user input. Defined using class variables
            commit (bool): a bool that determines to commit or not to commit the changes to database
                        (since Netbox automatically reverts database changes on commit = False, we don't use it)

        Returns:
            str: output for the Output tab
        """
        output = ""
        devices = Device.objects.filter(name__regex=data["device_name"])

        for device in devices:
            netbox_interfaces = Interface.objects.filter(device=device.id)
            napalm_interfaces = napalm_call("get_interfaces", device.id, self.request)

            for napalm_interface in napalm_interfaces:
                # Blacklist interfaces
                if data["ignore_interfaces"] != "" and re.match(
                    data["ignore_interfaces"], napalm_interface
                ):
                    continue

                napalm_description = napalm_interfaces[napalm_interface]["description"]

                mac_address = napalm_interfaces[napalm_interface]["mac_address"]
                if (
                    mac_address == "None"
                    and mac_address == "Unspecified"
                    and mac_address == ""
                ):
                    mac_address = None

                # We don't use update_or_create so we can inform the user when something actually updates
                # update_or_create will update even if nothing changes
                (netbox_interface, created) = netbox_interfaces.get_or_create(
                    name=napalm_interface,
                    defaults={
                        "type": InterfaceTypeChoices.TYPE_OTHER,
                        "description": napalm_description,
                        "device": device,
                        "mac_address": mac_address,
                    },
                )
                if created:
                    self.log_success(
                        f"`[{device.name}]` Created a new interface **({netbox_interface.name})**"
                    )
                else:
                    if netbox_interface.description != napalm_description:
                        old_description = netbox_interface.description
                        netbox_interface.description = napalm_description
                        netbox_interface.save()
                        self.log_success(
                            f"`[{device.name}]` Updated an interface's description **({netbox_interface.name})**: '{old_description}' -> '{napalm_description}'"
                        )

        return output
Пример #6
0
class MultiConnect(Script):
    class Meta:
        name = "Multi Connect"
        description = "Add multiple connections from one device to another"

    device_a = ObjectVar(model=Device, label="Device A")
    termination_type_a = ChoiceVar(choices=TERM_CHOICES,
                                   label="Device A port type")
    termination_name_a = StringVar(label="Device A port name pattern",
                                   description="Example: ge-0/0/[5,7,12-23]")

    device_b = ObjectVar(model=Device, label="Device B")
    termination_type_b = ChoiceVar(choices=TERM_CHOICES,
                                   label="Device B port type")
    termination_name_b = StringVar(label="Device B port name pattern",
                                   description="Example: ge-0/0/[5,7,12-23]")

    cable_status = ChoiceVar(choices=LinkStatusChoices.CHOICES,
                             default=LinkStatusChoices.STATUS_CONNECTED,
                             label="Cable Status")
    cable_type = ChoiceVar(choices=NO_CHOICE + CableTypeChoices.CHOICES,
                           required=False,
                           label="Cable Type")
    cable_tenant = ObjectVar(model=Tenant,
                             required=False,
                             label="Cable Tenant")
    cable_label = StringVar(label="Cable Label pattern", required=False)
    cable_color = ChoiceVar(choices=NO_CHOICE + ColorChoices.CHOICES,
                            required=False,
                            label="Cable Color")
    cable_length = IntegerVar(
        required=False,
        label="Cable Length")  # unfortunately there is no DecimalVar
    cable_length_unit = ChoiceVar(choices=NO_CHOICE +
                                  CableLengthUnitChoices.CHOICES,
                                  required=False,
                                  label="Cable Length Unit")
    cable_tags = MultiObjectVar(model=Tag, required=False, label="Cable Tags")

    def run(self, data, commit):
        device_a = data["device_a"]
        device_b = data["device_b"]
        ports_a = getattr(device_a, data["termination_type_a"]).all()
        ports_b = getattr(device_b, data["termination_type_b"]).all()

        terms_a = expand_pattern(data["termination_name_a"])
        terms_b = expand_pattern(data["termination_name_b"])
        if len(terms_a) != len(terms_b):
            return self.log_failure(
                f'Mismatched number of ports: {len(terms_a)} (A) versus {len(terms_b)} (B)'
            )
        labels = expand_pattern(data["cable_label"])
        if len(labels) == 1:
            labels = [labels[0] for i in range(len(terms_a))]
        elif len(labels) != len(terms_a):
            return self.log_failure(
                f'Mismatched number of labels: {len(labels)} labels versus {len(terms_a)} ports'
            )

        for i in range(len(terms_a)):
            term_a = [x for x in ports_a if x.name == terms_a[i]]
            if len(term_a) != 1:
                self.log_failure(
                    f'Unable to find "{terms_a[i]}" in {data["termination_type_a"]} on device A ({device_a.name})'
                )
                continue
            term_b = [x for x in ports_b if x.name == terms_b[i]]
            if len(term_b) != 1:
                self.log_failure(
                    f'Unable to find "{terms_b[i]}" in {data["termination_type_b"]} on device B ({device_b.name})'
                )
                continue
            cable = Cable(
                termination_a=term_a[0],
                termination_b=term_b[0],
                type=data["cable_type"],
                status=data["cable_status"],
                tenant=data["cable_tenant"],
                label=labels[i],
                color=data["cable_color"],
                length=data["cable_length"],
                length_unit=data["cable_length_unit"],
            )
            try:
                with transaction.atomic():
                    cable.full_clean()
                    cable.save()
                    cable.tags.set(data["cable_tags"])
            except Exception as e:
                self.log_failure(
                    f'Unable to connect {device_a.name}:{terms_a[i]} to {device_b.name}:{terms_b[i]}: {e}'
                )
                continue
            self.log_success(
                f'Created cable from {device_a.name}:{terms_a[i]} to {device_b.name}:{terms_b[i]}'
            )
Пример #7
0
class CableUpdate(Script):
    """Script that can be used to auto generate interfaces from devices using NAPALM

    Args:
        Script (:obj:`extras.script.Script`): Netbox Script object that is needed for a class to be recognized as one
    """
    class Meta:
        """Special class that is used for defining script information"""

        name = "Cable update"
        description = "Script that updates cable connections between network interfaces"
        commit_default = False

    device_name = StringVar(
        label="Devices regex",
        default="(r6|v22)-leaf((1\d*|[2-9])|1)",
        description=
        "Regex that will be used to select devices that will have their interfaces cabled",
        required=True,
    )

    non_existent = BooleanVar(
        label="Non-existent devices",
        default=False,
        description=
        "If the warnings about non-existent devices/interfaces will be shown",
    )

    def run(self, data, commit: bool):
        """The main method of the script that will be run when pressing the Run Script button

        1. Grabs the data from Netbox about devices containing the devices by regex input by the user
        2. Loops through the devices, and makes a NAPALM `get_lldp_neighbors` call to gather local and their remote interfaces
        3. Loops through all LLDP provided local interfaces.
        4. If a mac_address is any kind of empty or null, it makes sure to set it to python None
        5. Makes sure the local interface can be found in Netbox
        6. If a cable is found, it moves to the next iteration and if the remote interface is correct, goes to next iteration
        7. If a cable is found but the remote interface is not the same, makes sure to mark the cable for deletion (Netbox only allows 1 to 1 cable connections)
        8. Makes sure the remote device and interface can be found in Netbox
        9. Deletes the cable if one was found
        10. Creates a new cable using the local and remote interface pair
        11. Calls function to remove cables no longer found in LLDP

        Args:
            data (dict): a dict that has the variables for user input. Defined using class variables
            commit (bool): a bool that determines to commit or not to commit the changes to database
                        (since Netbox automatically reverts database changes on commit = False, we don't use it)

        Returns:
            str: output for the Output tab
        """
        output = ""
        devices = Device.objects.filter(name__regex=data["device_name"])

        for device in devices:
            napalm_lldp_neighbors = napalm_call("get_lldp_neighbors",
                                                device.id, self.request)

            lldp_interface_names = []
            for local_interface_name, remote_interface in napalm_lldp_neighbors.items(
            ):
                remote_device_name = remote_interface[0]["hostname"]
                remote_interface_name = remote_interface[0]["port"]

                lldp_interface_names.append(local_interface_name)
                try:
                    netbox_local_interface = Interface.objects.get(
                        device=device.id, name=local_interface_name)
                except Interface.DoesNotExist:
                    if data["non_existent"]:
                        self.log_warning(
                            f"""`[{device.name}]` Local interface **({local_interface_name})** for device **({device.name})** could not be found in Netbox.  
                            Please run the interface update script to have all the interfaces for a device generated"""
                        )
                    continue

                delete_cable = False
                if netbox_local_interface.cable is not None:
                    if (netbox_local_interface._cable_peer.name
                            == remote_interface_name
                            and netbox_local_interface._cable_peer.device.name
                            == remote_device_name):
                        # Cable already exists so we continue on
                        continue
                    else:  # A Netbox cable is connected but not to the interface the device is reporting
                        delete_cable = True  # Don't delete the cable immediately as the remote interface might not be there

                try:
                    remote_device = Device.objects.get(name=remote_device_name)
                    netbox_remote_interface = Interface.objects.get(
                        device=remote_device.id, name=remote_interface_name)
                except Device.DoesNotExist:
                    if data["non_existent"]:
                        self.log_info(
                            f"""`[{device.name}]` Remote device **({remote_device_name})** could not be found in Netbox  
                            Create the device in Netbox and add the **({remote_interface_name})** interface for a cable to be connected"""
                        )
                    continue
                except Interface.DoesNotExist:
                    if data["non_existent"]:
                        self.log_info(
                            f"""`[{device.name}]` Remote Interface **({remote_interface_name})** for device **({remote_device_name})** could not be found in Netbox  
                            Create the interface in Netbox for a cable to be connected"""
                        )
                    continue

                if delete_cable:
                    # Delete a cable that doesn't exist
                    netbox_local_interface.cable.delete()
                    self.log_success(
                        f"`[{device.name}]` Deleting a no longer existing cable: "
                        f"**{netbox_local_interface.name}** "
                        f"({netbox_local_interface.device.name})"
                        " <-> "
                        f"**{netbox_local_interface._cable_peer.name}** "
                        f"({netbox_local_interface._cable_peer.device.name})")

                # Create a new cable
                dcim_interface_type = ContentType.objects.get(
                    app_label="dcim", model="interface")
                new_cable = Cable(
                    termination_a_type=dcim_interface_type,
                    termination_a_id=netbox_local_interface.id,
                    termination_b_type=dcim_interface_type,
                    termination_b_id=netbox_remote_interface.id,
                )
                new_cable.save()

                self.log_success(f"`[{device.name}]` Creating a new cable: "
                                 f"**{netbox_local_interface.name}** "
                                 f"({netbox_local_interface.device.name})"
                                 " <-> "
                                 f"**{netbox_remote_interface.name}** "
                                 f"({netbox_remote_interface.device.name})")
            self.remove_old_cables(device, lldp_interface_names)

        return output

    def remove_old_cables(self, device, lldp_interface_names: List[str]):
        """Task that will remove cables that are no longer connected based on LLDP data

        1. Grabs all the interfaces from the specific device, if it has a Netbox cable attached
            and if it wasn't one of the local interfaces returned from LLDP
        2. Loops through them and deletes them

        Args:
            device (:obj:`dcim.models.Device`):
                A Netbox device model of the device that will be checked for old cables
            lldp_interface_names (:obj:`List[str]`):
                A List of local intefaces that have a cable attached from LLDP
        """
        old_cable_interfaces = Interface.objects.filter(
            device=device.id,
            cable__isnull=False).exclude(name__in=lldp_interface_names)

        for oc_interface in old_cable_interfaces:
            try:
                old_cable = oc_interface.cable
            except:
                # The cable could have already been deleted if it was plugged in the same device
                continue

            old_cable.delete()
            self.log_success(f"`[{device.name}]` Deleting an old cable: "
                             f"**{old_cable.termination_a.name}** "
                             f"({old_cable.termination_a.device.name})"
                             " <-> "
                             f"**{old_cable.termination_b.name}** "
                             f"({old_cable.termination_b.device.name})")
Пример #8
0
class NewVM(Script):
    class Meta:
        name = "New VM"
        description = "Create a new VM"
        field_order = [
            'vm_name',
            'dns_name',
            'primary_ip4',
            'primary_ip6',  #'vrf',
            'role',
            'status',
            'cluster',  #'tenant',
            'platform',
            'interface_name',
            'mac_address',
            'vcpus',
            'memory',
            'disk',
            'comments',
            'pve_host'
        ]

    vm_name = StringVar(label="VM name")
    dns_name = StringVar(label="DNS name", required=False)
    primary_ip4 = IPAddressWithMaskVar(label="IPv4 address")
    # primary_ip6 = IPAddressWithMaskVar(label="IPv6 address", required=False)
    # vrf = ObjectVar(VRF.objects, required=False)
    role = ObjectVar(DeviceRole.objects.filter(vm_role=True),
                     required=False,
                     default=8)
    status = ChoiceVar(VirtualMachineStatusChoices,
                       default=VirtualMachineStatusChoices.STATUS_ACTIVE)
    # cluster = ObjectVar(Cluster.objects)
    # tenant = ObjectVar(Tenant.objects, required=False)
    # platform = ObjectVar(Platform.objects, required=False)
    interface_name = StringVar(default="eth0")
    # mac_address = StringVar(label="MAC address", required=False)
    vcpus = IntegerVar(label="VCPUs", required=True)
    memory = IntegerVar(label="Memory (MB)", required=True)
    disk = IntegerVar(label="Disk (GB)", required=True)
    comments = TextVar(label="Comments", required=False)
    # pve_host = ObjectVar(Device.objects.filter(cluster__name='Newtelco Cluster'), label="Proxmox Host", required=True)
    PVE_DEVICES = (('nt-pve', 'nt-pve'), ('nt-pve2', 'nt-pve2'),
                   ('nt-pve5', 'nt-pve5'), ('nt-pve6', 'nt-pve6'))
    pve_host = ChoiceVar(choices=PVE_DEVICES)

    # pve_host_ip=Device.objects.filter(name=pve_host)

    def run(self, data, commit):
        pve_host = Device.objects.filter(name=data["pve_host"])
        vm = VirtualMachine(
            name=data["vm_name"],
            role=data["role"],
            status=data["status"],
            vcpus=data["vcpus"],
            memory=data["memory"],
            disk=data["disk"],
            comments=data["comments"],
        )
        if commit:
            vm.save()

        interface = Interface(
            name=data["interface_name"],
            type=InterfaceTypeChoices.TYPE_VIRTUAL,
            virtual_machine=vm,
        )
        if commit:
            interface.save()

        def add_addr(addr, expect_family):
            if not addr:
                return
            if addr.version != expect_family:
                raise RuntimeError("Wrong family for %r" % a)
            try:
                a = IPAddress.objects.get(
                    address=addr,
                    family=addr.version,
                    vrf=data.get("vrf"),
                )
                result = "Assigned"
            except ObjectDoesNotExist:
                a = IPAddress(
                    address=addr,
                    family=addr.version,
                    vrf=data.get("vrf"),
                )
                result = "Created"
            a.status = IPAddressStatusChoices.STATUS_ACTIVE
            a.dns_name = data["dns_name"]
            if a.interface:
                raise RuntimeError("Address %s is already assigned" % addr)
            a.interface = interface
            a.tenant = data.get("tenant")
            a.save()
            self.log_info("%s IP address %s %s" %
                          (result, a.address, a.vrf or ""))
            setattr(vm, "primary_ip%d" % a.family, a)

        def connect_pve(addr):
            self.log_info(addr)
            proxmox = ProxmoxAPI(
                addr,
                user='******',
                token_name='nb1',
                token_value='0cf6ab07-ff7e-41a3-80e4-e09e7fea6c7d',
                verify_ssl=False)
            self.log_success(proxmox.nodes.get())

        # self.log_info(data["pve_host"])
        pve_ip = str(pve_host.get().primary_ip4)[:-3]
        self.log_info(pve_ip)
        connect_pve(pve_ip)
        if commit:
            add_addr(data["primary_ip4"], 4)
            # add_addr(data["primary_ip6"], 6)
            vm.save()
            self.log_success("Created VM %s" % vm.name)
        else:
            self.log_success("Dry-run Success - Created VM %s" % vm.name)
Пример #9
0
class NewVM(Script):
    class Meta:
        name = "New VM"
        description = "Create a new VM"

    vm_name = StringVar(label="VM name")
    dns_name = StringVar(label="DNS name", required=False)
    vm_tags = MultiObjectVar(model=Tag, label="VM tags", required=False)
    primary_ip4 = IPAddressWithMaskVar(label="IPv4 address")
    #primary_ip4_tags = MultiObjectVar(model=Tag, label="IPv4 tags", required=False)
    primary_ip6 = IPAddressWithMaskVar(label="IPv6 address", required=False)
    #primary_ip6_tags = MultiObjectVar(model=Tag, label="IPv6 tags", required=False)
    #vrf = ObjectVar(model=VRF, required=False)
    role = ObjectVar(model=DeviceRole,
                     query_params=dict(vm_role=True),
                     required=False)
    status = ChoiceVar(VirtualMachineStatusChoices,
                       default=VirtualMachineStatusChoices.STATUS_ACTIVE)
    cluster = ObjectVar(model=Cluster)
    tenant = ObjectVar(model=Tenant, required=False)
    platform = ObjectVar(model=Platform, required=False)
    interface_name = StringVar(default="eth0")
    mac_address = StringVar(label="MAC address", required=False)
    vcpus = IntegerVar(label="VCPUs", required=False)
    memory = IntegerVar(label="Memory (MB)", required=False)
    disk = IntegerVar(label="Disk (GB)", required=False)
    comments = TextVar(label="Comments", required=False)

    def run(self, data, commit):
        vm = VirtualMachine(
            name=data["vm_name"],
            role=data["role"],
            status=data["status"],
            cluster=data["cluster"],
            platform=data["platform"],
            vcpus=data["vcpus"],
            memory=data["memory"],
            disk=data["disk"],
            comments=data["comments"],
            tenant=data.get("tenant"),
        )
        vm.full_clean()
        vm.save()
        vm.tags.set(data["vm_tags"])

        vminterface = VMInterface(
            name=data["interface_name"],
            mac_address=data["mac_address"],
            virtual_machine=vm,
        )
        vminterface.full_clean()
        vminterface.save()

        def add_addr(addr, family):
            if not addr:
                return
            if addr.version != family:
                raise RuntimeError(f"Wrong family for {a}")
            try:
                a = IPAddress.objects.get(
                    address=addr,
                    vrf=data.get("vrf"),
                )
                result = "Assigned"
            except ObjectDoesNotExist:
                a = IPAddress(
                    address=addr,
                    vrf=data.get("vrf"),
                )
                result = "Created"
            a.status = IPAddressStatusChoices.STATUS_ACTIVE
            a.dns_name = data["dns_name"]
            if a.assigned_object:
                raise RuntimeError(f"Address {addr} is already assigned")
            a.assigned_object = vminterface
            a.tenant = data.get("tenant")
            a.full_clean()
            a.save()
            #a.tags.set(data[f"primary_ip{family}_tags"])
            self.log_info(f"{result} IP address {a.address} {a.vrf or ''}")
            setattr(vm, f"primary_ip{family}", a)

        add_addr(data["primary_ip4"], 4)
        add_addr(data["primary_ip6"], 6)
        vm.full_clean()
        vm.save()
        self.log_success(
            f"Created VM [{vm.name}](/virtualization/virtual-machines/{vm.id}/)"
        )