GithubHelp home page GithubHelp logo

netbox-community / ansible_modules Goto Github PK

View Code? Open in Web Editor NEW
309.0 22.0 199.0 4.26 MB

NetBox modules for Ansible using Ansible Collections

License: GNU General Public License v3.0

Python 98.46% Shell 1.54%

ansible_modules's Introduction

Ansible Modules for NetBox

Description

The NetBox Ansible project provides an Ansible collection for interacting with NetBox, the leading solution for modeling and documenting modern networks. By combining the traditional disciplines of IP address management (IPAM) and datacenter infrastructure management (DCIM) with powerful APIs and extensions, NetBox provides the ideal "source of truth" to power network automation.

This Ansible collection consists of a set of modules to define the intended network state in NetBox, along with plugins to drive automation of the network using data from NetBox.

Requirements

  • You must be running one of the two most recent releases of NetBox
  • A NetBox write-enabled API token when using modules or a read-only token for the nb_lookup and nb_inventory plugins.
  • Python 3.10+
  • Python modules:
    • pytz
    • pynetbox
  • Ansible 2.15+

Installation

Python Modules and Ansible

pip install pytz
pip install pynetbox
pip install ansible

NetBox Ansible Collection

Before using this collection, you need to install it with the Ansible Galaxy command-line tool:

ansible-galaxy collection install netbox.netbox

You can also include it in a requirements.yml file and install it with ansible-galaxy collection install -r requirements.yml, using the format:

collections:
  - name: netbox.netbox

To upgrade the collection to the latest available version, run the following command:

ansible-galaxy collection install netbox.netbox --upgrade

You can also install a specific version of the collection, for example, if you need to downgrade when something is broken in the latest version (please report an issue in this repository). Use the following syntax to install version 3.19.1:

ansible-galaxy collection install netbox.netbox:==3.19.1

See using Ansible collections for more details.

Other Installation Options

Build From Source

Follow these steps to install from source:

  1. git clone [email protected]:netbox-community/ansible_modules.git
  2. cd ansible_modules
  3. ansible-galaxy collection build .
  4. ansible-galaxy collection install netbox-netbox*.tar.gz

Build From Source (Pull Request)

This is useful to test code within PRs.

  1. git clone [email protected]:netbox-community/ansible_modules.git
  2. cd ansible_modules
  3. git fetch origin pull/<pr #>/head:<whatever-name-you-want>
  4. git checkout <whatever-name-you-want>
  5. ansible-galaxy collection build .
  6. ansible-galaxy collection install netbox-netbox*.tar.gz

Note: This GitHub link provides detailed information on checking out pull requests locally.

Use Cases

Use Case 1 - Define Intended Network State in NetBox

Define the intended state of your network in NetBox, by interacting with the NetBox database to define objects and their associated state in the following ways:

  • Make sure objects exit
  • Update objects if they do exist
  • Remove objects if they do not not exist

For example, to make sure a new aggregate network prefix exists:

tasks:
    - name: Create aggregate within NetBox with only required information
      netbox.netbox.netbox_aggregate:
        netbox_url: http://netbox.local
        netbox_token: thisIsMyToken
        data:
          prefix: 192.168.0.0/16
          rir: Test RIR
        state: present

Use Case 2 - NetBox as a Dynamic Inventory Source for Ansible

Use the Inventory Plugin to dynamically generate Ansible inventory from device data in NetBox. Use query filters, groups and mappings to tailor the generated inventory to your specific needs.

The following example builds an Ansible inventory that groups devices by role, and filters for only devices that have the network-edge-router role, have a primary IP address and belong to the internal tenant:

# netbox_inventory.yml file in YAML format
# Example command line: ansible-inventory -v --list -i netbox_inventory.yml

plugin: netbox.netbox.nb_inventory
api_endpoint: http://localhost:8000
validate_certs: True
config_context: False
group_by:
  - device_roles
query_filters:
  - role: network-edge-router
device_query_filters:
  - has_primary_ip: 'true'
  - tenant__n: internal

Use Case 3 - Query and Return Elements from NetBox

Use the Lookup plugin to query NetBox and return data to drive network automation, such as lists of devices, device configurations, prefixes and IP addresses etc.

The following example returns a list of devices and their manufacturers, using an API filter to only return devices with the management role and the NetBox tag of Dell:

tasks:
  # query a list of devices
  - name: Obtain list of devices from NetBox
    debug:
      msg: >
        "Device {{ item.value.display_name }} (ID: {{ item.key }}) was
         manufactured by {{ item.value.device_type.manufacturer.name }}"
    loop: "{{ query('netbox.netbox.nb_lookup', 'devices',
                    api_endpoint='http://localhost/',
                    api_filter='role=management tag=Dell'),
                    token='<redacted>') }}"

Testing

Tested with Ansible Core v2.15+ Ansible Core versions prior to 2.15 are not supported.

Contributing

If you would to contribute to the project then you can find out how to get started here.

Support

There are various options to get support for the collection:

Customers of NetBox Labs and Ansible using the officially certified version of the collection can get support via the usual Ansible channels. Escalation to the NetBox Labs support team will be provided as needed.

Release Notes

The collection release notes and changelog can be found here.

Related Information

Some extra resources you might find useful for both the Anisble collection and for NetBox itself:

License Information

GNU General Public License v3.0 or later.

See LICENSE for the full text of the license.

Link to the license that the collection is published under.

ansible_modules's People

Contributors

2bithacker avatar aaron-iles avatar andrii-konts avatar andybro19 avatar bdrung avatar bluikko avatar bvergnaud avatar cfiehe avatar cyrilpop avatar dependabot[bot] avatar devon-mar avatar douglasheriot avatar eric-sim avatar fragmentedpacket avatar jeremystretch avatar k-304 avatar mindbreak avatar minitriga avatar mrdiba avatar nahun avatar pkorovin avatar richbibby avatar rodvand avatar rokernel avatar ryanmerolle avatar sapergus avatar sc68cal avatar shourai avatar thomasadavis avatar toerb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ansible_modules's Issues

add support for custom_fields for netbox_virtual_machine

ISSUE TYPE
  • Feature Idea
SUMMARY

It would be great to support custom_fields for netbox_virtual_machine

STEPS TO REPRODUCE
    - name: Create VMs 
      fragmentedpacket.netbox_modules.netbox_virtual_machine:
        netbox_url: "{{ netbox_url }}"
        netbox_token: "{{ netbox_token }}"
        data:
          name: "{{ item.name }}"
          cluster: "{{ item.cluster  }}"
          virtual_machine_role: "{{ item.virtual_machine_role|default(omit) }}"
          vcpus: "{{ item.vcpus|default(omit) }}"
          tenant: "{{ item.tenant|default(omit) }}"
          platform: "{{ item.platform|default(omit) }}"
          memory: "{{ item.memory|default(omit) }}"
          disk: "{{ item.disk|default(omit) }}"
          status: "{{ item.status|default(Active) }}"
          tags: "{{ item.tags|default(omit) }}"
          custom_fields: "{{ item.custom_fields|default(omit) }}"
        state: "{{ item.state|default(omit) }}"
      run_once: true
      delegate_to: localhost
      become: false
      loop: "{{ netbox_virtual_machines }}"
      when: netbox_virtual_machines is defined
ACTUAL RESULTS

custom_fields are ignored

Netbox_interface : Fail to modify interface within a virtual chassis #67578

ISSUE TYPE
  • Bug Report
SUMMARY

Hi !
I have 2 devices, in a virtual chassis.
virtual_chassis

The interface Ethernet1 is configured on the non-master device

before

On netbox, i see this interface in the virtual-chassis master's interfaces, which is fine.
When i try to modify an interface within a virtual chassis with the netbox_interface module, it deletes the interfaces from the secondary device and creates it on the master device
after_slave
after_master

STEPS TO REPRODUCE
  • Create two devices in netbox.
  • Gather them with a virtual chassis (choose a master and a slave)
  • Create interface on the slave device
  • Run the playbook
  • Notice that the interface disapeared on the slave device and appeared on the master.
- name: "Playbook"
  vars :
    nb_addr: "your_nb_address"
    nb_token: "your_token"
  tasks:
    - name :  Create or modify interface
      netbox_interface:
        netbox_url: "{{ nb_addr }}"
        netbox_token: "{{ nb_token }}"
        data:
          device: "ROUTER1"
          name: "Ethernet1"
          description: "Description change"
      delegate_to: 127.0.0.1
EXPECTED RESULTS

I expect interface on the secondary device to be modified

ACTUAL RESULTS
ansible-playbook 2.9.4
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/dist-packages/ansible
  executable location = /usr/bin/ansible-playbook
  python version = 2.7.13 (default, Sep 26 2018, 18:42:22) [GCC 6.3.0 20170516]
Using /etc/ansible/ansible.cfg as config file
setting up inventory plugins
host_list declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
script declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
auto declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
Parsed /etc/ansible/hosts inventory source with ini plugin
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

Loading callback plugin default of type stdout, v2.0 from /usr/lib/python2.7/dist-packages/ansible/plugins/callback/default.pyc

PLAYBOOK: module.yml **********************************************************************************************************************************************************************************************************************************************************
Positional arguments: module.yml
become_method: sudo
inventory: (u'/etc/ansible/hosts',)
forks: 5
tags: (u'all',)
verbosity: 4
connection: smart
timeout: 10
1 plays in module.yml

PLAY [Get port configuration and save in Netbox] ******************************************************************************************************************************************************************************************************************************
META: ran handlers

TASK [Create or modify access interface] **************************************************************************************************************************************************************************************************************************************
task path: /root/netbox_issue/module.yml:12
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: root
<127.0.0.1> EXEC /bin/sh -c 'echo ~root && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /root/.ansible/tmp/ansible-tmp-1582127139.71-92714538077148 `" && echo ansible-tmp-1582127139.71-92714538077148="` echo /root/.ansible/tmp/ansible-tmp-1582127139.71-92714538077148 `" ) && sleep 0'
Using module file /usr/lib/python2.7/dist-packages/ansible/modules/net_tools/netbox/netbox_interface.py
<127.0.0.1> PUT /root/.ansible/tmp/ansible-local-22430U44jhB/tmpsR8lNO TO /root/.ansible/tmp/ansible-tmp-1582127139.71-92714538077148/AnsiballZ_netbox_interface.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1582127139.71-92714538077148/ /root/.ansible/tmp/ansible-tmp-1582127139.71-92714538077148/AnsiballZ_netbox_interface.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1582127139.71-92714538077148/AnsiballZ_netbox_interface.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-tmp-1582127139.71-92714538077148/ > /dev/null 2>&1 && sleep 0'
changed: [localhost -> 127.0.0.1] => {
    "changed": true,
    "diff": {
        "after": {
            "description": "Description change",
            "device": 1
        },
        "before": {
            "description": "",
            "device": 3
        }
    },
    "interface": {
        "cable": null,
        "connected_endpoint": null,
        "connected_endpoint_type": null,
        "connection_status": null,
        "count_ipaddresses": 0,
        "description": "Description change",
        "device": 1,
        "enabled": true,
        "id": 540,
        "lag": null,
        "mac_address": null,
        "mgmt_only": false,
        "mode": null,
        "mtu": null,
        "name": "Ethernet1",
        "tagged_vlans": [],
        "tags": [],
        "type": "virtual",
        "untagged_vlan": null
    },
    "invocation": {
        "module_args": {
            "data": {
                "description": "Description change",
                "device": 1,
                "name": "Ethernet1"
            },
            "netbox_token": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "netbox_url": "http://192.168.150.100:8000",
            "state": "present",
            "validate_certs": true
        }
    },
    "msg": "Interface Ethernet1 updated"
}
META: ran handlers
META: ran handlers

PLAY RECAP ********************************************************************************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Updating name of manufacturer is not possible

ISSUE TYPE
  • Bug Report
SUMMARY

Updating manufacturers does not work, instead of updating name it fails.

STEPS TO REPRODUCE
- netbox_manufacturers:
    data:
      name: "{{ item }}"
  loop:
    - dell
    - Dell
EXPECTED RESULTS

Manufacturer dell is created and then the name for it is updated to Dell

ACTUAL RESULTS
{"slug":["manufacturer with this slug already exists."]}

Include Ansible Inventory plugin too?

ISSUE TYPE
  • Feature Idea

Should the Netbox inventory plugin also be copied to this separate repo for development separate to Ansible core?

There's open pull requests that are taking some time to be merged, and I'd love to avoid them being tied to waiting for Ansible releases.

Missing modules

Hi,

My ansible conf:

ansible 2.9.4 config file = /etc/ansible/ansible.cfg configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/local/lib/python3.6/site-packages/ansible executable location = /usr/local/bin/ansible python version = 3.6.8 (default, Aug 7 2019, 17:28:10) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
Installed Netbox modules:

ansible-galaxy collection install netbox_community.ansible_modules Process install dependency map Starting collection install process Installing 'netbox_community.ansible_modules:0.1.4' to '/root/.ansible/collections/ansible_collections/netbox_community/ansible_modules' [root@NETBOX caio]# ansible-doc netbox_vrf

Failing when trying to use a few modules:

# ansible-doc netbox_vrf [WARNING]: module netbox_vrf not found in: /root/.ansible/plugins/modules:/usr/ share/ansible/plugins/modules:/usr/local/lib/python3.6/site- packages/ansible/modules

# ansible-doc netbox_tenant [WARNING]: module netbox_tenant not found in: /root/.ansible/plugins/modules:/u sr/share/ansible/plugins/modules:/usr/local/lib/python3.6/site- packages/ansible/modules

What did I miss?

Thanks.

netbox_device_role is not reporting an error when color is missing

ISSUE TYPE
  • Bug Report
SUMMARY

The module not returning an error when color is missing

STEPS TO REPRODUCE

I tried to create new device_role using the netbox_device_role module but I forgot to specify color

- name: Create Device Role in Netbox
      netbox_device_role:
        netbox_url: "{{ netbox_address }}"
        netbox_token: "{{ netbox_token }}"
        data:
          name: "{{role}}"
          color: 
        state: present
      delegate_to: localhost
      tags: [device_role]
EXPECTED RESULTS

I would expect the execution to fail since color is mandatory

ACTUAL RESULTS

The module is not reporting an error and unless running in debug more there is no indication that something is wrong

ok: [mydevice -> localhost] => {
    "changed": false,
    "invocation": {
        "module_args": {
            "data": {
                "name": "myrole",
                "slug": "myrole"
            },
            "netbox_token": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "netbox_url": "http://host.docker.internal:8001",
            "state": "present",
            "validate_certs": true
        }
    },
    "msg": "{\"color\":[\"This field is required.\"]}"
}

Feature: Improve the extendability of the netbox inventory plugin

ISSUE TYPE
  • Feature Idea
SUMMARY

Separating the list of lookup functions from the logic that executes the lookups. This will improve the extendability of the inventory plugin by allowing the addition of more lookups without having to re-implement or change the refresh_lookups method.

Original Ansible Core PR:
ansible/ansible#59662

@ChrisPortman since you're the original author of this PR, could you submit a new one to this repo? We're pulling the latest devel version of the Inventory plugin out of Ansible Core and into this collection for future development.

Feature: Add Netbox Services

ISSUE TYPE
  • Feature Idea
SUMMARY

Feature could be used to configure monitoring systems by addition of services defined in Netbox in Ansible hostvars. Netbox allows arbitrary structured data to be assigned to servers via custom fields, tags, configuration contexts and services.

Original Related Ansible Core Issues:
ansible/ansible#47918
ansible/ansible#47919

@ollybee we've pulled the Inventory plugin out of core and into this collection. Could you please submit a new PR to this issue with your changes?

Still seeing the msg: 'Multiple results found while searching for key: rack'

ISSUE TYPE
  • Module question
  • Documentation update
SUMMARY

Not sure how to verify that the collections are working or being used? I really want to use your modules to manage our Netbox instance, but after installing the prerequisites, and the collections via ansible-galaxy and tagging them in the playbook I still see the rack key error.

I know that the rack name is unique within our Netbox deployment.

STEPS TO REPRODUCE
# PLAYBOOK
---
- name: "Test Netbox modules"
  connection: local
  hosts: localhost
  gather_facts: False
  collections:
    - fragmentedpacket.netbox_modules

  vars_files:
    - /home/flynn/ansible/playbooks/netbox/vault/netbox
    #- /home/flynn/ansible/playbooks/netbox/group_vars/nasuni.yml
    - /home/flynn/ansible/playbooks/netbox/group_vars/test_data.yml

  roles:
    - netbox_add_device
    - netbox_assign_ip

# ROLE
---
# tasks file for netbox_add_device
    - name: "Create device within Netbox with only required information"
      netbox_device:
        netbox_url: 
        netbox_token: "{{  netbox_key  }}"
        data:
          name: "{{ item.value.dname }}"
          device_type: "{{ item.value.dtype }}"
          device_role: "{{ item.value.drole }}"
          site: "{{ item.value.dsite }}"
          rack: "{{ item.value.drack }}"
          position: "{{ item.value.dposition }}"
          face: "{{ item.value.dface }}"
          state: "{{ item.value.dstate }}"
        state: present
      loop: "{{ query('dict', devices) }}"
      tags: add_device
EXPECTED RESULTS
ACTUAL RESULTS
*
failed: [localhost] (item={'key': u'device1', 'value': {u'dname': u'test.machine.net', u'dtype': u'Edge Appliance N4040', u'dstate': u'Planned', u'drack': u'TEST-NEW-RACK-01', u'dsite': u'TEST', u'drole': u'NAS', u'dface': u'Front', u'dposition': u'16'}}) => changed=false
  ansible_facts:
    discovered_interpreter_python: /usr/bin/python
  ansible_loop_var: item
  item:
    key: device1
    value:
      dface: Front
      dname: test.machine.net
      dposition: '16'
      drack: TEST-NEW-RACK-01
      drole: NAS
      dsite: TEST
      dstate: Planned
      dtype: Edge Appliance N4040
  msg: 'Multiple results found while searching for key: rack'


Getting issues when added racks to rack group

ISSUE TYPE
  • Bug Report
SUMMARY

I see an error when trying to add racks to a rack group

STEPS TO REPRODUCE

Using the netbox_rack_groups and netbox_racks collections to add a rack group and racks.

    - name: "Create rack group in Netbox"
      fragmentedpacket.netbox_modules.netbox_rack_group:
        netbox_url: 
        netbox_token: "{{  netbox_key  }}"
        data:
          site: "{{ item.value.sitename }}"
          name: "{{ item.value.rackgroupname }}"
        state: present
      #check_mode: yes
      loop: "{{ query('dict', rackgroups) }}"
      #when: "{{ item.value.drack }}" != ""
      tags: add_rack_group

# task add racks to rack group
    - name: "Create racks and add to rack group in Netbox"
      fragmentedpacket.netbox_modules.netbox_rack:
        netbox_url: 
        netbox_token: "{{  netbox_key  }}"
        data:
          site: "{{ item.value.sitename }}"
          name: "{{ item.value.rackname }}"
          group: "{{ item.value.group_name }}"
          serial_number: "{{ item.value.serialnumber | default(omit) }}"
          asset_tag: "{{ item.value.assettag | default(omit) }}"
          type: "{{ item.value.type }}"
          width: "{{ item.value.width }}"
          height: "{{ item.value.height }}"
        state: present
      #check_mode: yes
      loop: "{{ query('dict', racks) }}"
      #when: "{{ item.value.drack }}" != ""
      tags: add_racks
EXPECTED RESULTS

It would add the rack group

ACTUAL RESULTS

I get an error:
msg: 'Could not resolve id of group: yok-mdf-01

flynn@ncl-ansible-01:~/ansible/playbooks/netbox$ ansible-playbook netbox_add_devices.yaml --tags "add_rack_group,add_racks"

PLAY [Add devices to netbox] ***********************************************************************************************************************************************************************

TASK [netbox_build_racks : Create rack group in Netbox] ********************************************************************************************************************************************
ok: [localhost] => (item={'key': u'rackgroup1', 'value': {u'sitename': u'YOK', u'rackgroupname': u'YOK-MDF-01'}})

TASK [netbox_build_racks : Create racks and add to rack group in Netbox] ***************************************************************************************************************************
failed: [localhost] (item={'key': u'rack2', 'value': {u'sitename': u'YOK', u'serialnumber': u'', u'group_name': u'YOK-MDF-01', u'width': u'19 inches', u'assettag': u'', u'rackname': u'YOK-MDF-01-RACK-02', u'height': u'42', u'type': u'4-post cabinet'}}) => changed=false
  ansible_loop_var: item
  item:
    key: rack2
    value:
      assettag: ''
      group_name: YOK-MDF-01
      height: '42'
      rackname: YOK-MDF-01-RACK-02
      serialnumber: ''
      sitename: YOK
      type: 4-post cabinet
      width: 19 inches
  msg: 'Could not resolve id of group: yok-mdf-01'
failed: [localhost] (item={'key': u'rack3', 'value': {u'sitename': u'YOK', u'serialnumber': u'', u'group_name': u'YOK-MDF-01', u'width': u'19 inches', u'assettag': u'', u'rackname': u'YOK-MDF-01-RACK-03', u'height': u'42', u'type': u'4-post cabinet'}}) => changed=false
  ansible_loop_var: item
  item:
    key: rack3
    value:
      assettag: ''
      group_name: YOK-MDF-01
      height: '42'
      rackname: YOK-MDF-01-RACK-03
      serialnumber: ''
      sitename: YOK
      type: 4-post cabinet
      width: 19 inches
  msg: 'Could not resolve id of group: yok-mdf-01'
failed: [localhost] (item={'key': u'rack1', 'value': {u'sitename': u'YOK', u'serialnumber': u'', u'group_name': u'YOK-MDF-01', u'width': u'19 inches', u'assettag': u'', u'rackname': u'YOK-MDF-01-RACK-01', u'height': u'42', u'type': u'4-post cabinet'}}) => changed=false
  ansible_loop_var: item
  item:
    key: rack1
    value:
      assettag: ''
      group_name: YOK-MDF-01
      height: '42'
      rackname: YOK-MDF-01-RACK-01
      serialnumber: ''
      sitename: YOK
      type: 4-post cabinet
      width: 19 inches
  msg: 'Could not resolve id of group: yok-mdf-01'

Update Unit tests

ISSUE TYPE
  • Update Tests
SUMMARY

Need to parametrize unit tests a bit more
Possibly add tests for each module_util as well

Update readme post repo transfer

ISSUE TYPE
  • Documentation update
SUMMARY

The readme links and examples should be updated to reflect the repo transfer and renaming.

Netbox lookup plugin implies decrypting secrets is not supported when it is

ISSUE TYPE
  • Documentation update
SUMMARY

My documentation for Netbox lookup implies that decrypting secrets is not yet supported. I'm not sure why I got the idea that this didn't work when I first wrote the module, but it now seems to and is in fact already implemented! The comments in the code should be removed and an example provided.

STEPS TO REPRODUCE

Documentation/Example update only

Module netbox_device_interface doesn't seems to work properly

ISSUE TYPE
  • Bug Report
SUMMARY

I'm currently using your collection with "netbox_device", "netbox_ip_address" and "netbox_device_interface". But with the last one it seem's that ansible doesn't find any action related.

Ansible version: 2.8.5
Netbox version: 2.6.5

I have this message :

"ERROR! no action detected in task. This often indicates a misspelled module name, or incorrect module path.

The offending line appears to be:

  • name: Create interface within Netbox with only required information
    ^ here"
STEPS TO REPRODUCE

I'm using examples in your modules documentation, so netbox_device and netbox_ip_address are working but not netbox_device_interface

- name: Create device within Netbox with only required information
  collections:
     - fragmentedpacket.netbox_modules
  netbox_device:
    netbox_url: "{{ net_url }}"
    netbox_token: "{{ net_token }}"
    data:
      name: "{{ inventory_hostname }}"
      device_type: "{{ type }}"
      platform: "{{ platform }}"
      device_role: "{{ role }}"
      site: "{{ site }}"
      rack: "{{ rack }}"
      position: "{{ position }}"
      face: "{{ face }}"
    state: "{{ state }}"

- name: Create device interface with only required information
  collections:
     - fragmentedpacket.netbox_modules
  netbox_device_interface:
    netbox_url: "{{ net_url }}"
    netbox_token: "{{ net_token }}"
    data:
      device: "{{ inventory_hostname }}"
      name: Vme.0
    state: "{{ state }}"

- name: Create management IP linked to the device
  collections:
     - fragmentedpacket.netbox_modules
  netbox_ip_address:
    netbox_url: "{{ net_url }}"
    netbox_token: "{{ net_token }}"
    data:
      address: "{{ ansible_host }}"
      description: "Mgmt : {{ inventory_hostname }}"
      interface:
        name: Vme.0
        device: "{{ inventory_hostname }}"
    state: "{{ state }}"
EXPECTED RESULTS

Create a device with one interface Vme.0 and one IP attached to it.

ACTUAL RESULTS

If i'm running the two task without netbox_device_interface, the device is created and i can create one IP.

So for the moment i'm using the official "netbox_interface" and it's working like expected.
But if i could use all your modules it would be great :)

Include the Netbox lookup plugin

@cpmills1975 has attempted to put together a generic lookup plugin designed to pull all information for a selected endpoint in to Ansible. This has not been reviewed by the Ansible developer community to this collection could be a good place to put it.

Use ansible facts to populate data?

Are there any plans to have the option to gather data about a device with ansible facts and then use the facts to populate device/inventory data in netbox?

I'm sorry if this has already been discussed or if it's perhaps already possible, I only took a quick glance and it didn't seem like it's possible currently.

Module does not flag unreachable netbox URL

ISSUE TYPE
  • Bug Report
SUMMARY

I mistakenly failed to wrap my netbox URL variable in quotes and curly brackets (e.g. I did netbox_url: nb_url instead of netbox_url: "{{ nb_url }}". Instead of failing with an error indicating that it could not reach this URL or could not correctly ping the API, it threw a device-specific error;

fatal: [lab-VM-host -> localhost]: FAILED! => changed=false
  msg: 'Multiple results found while searching for key: device'

Obviously this is a silly mistake on my part but I spent a significant amount of time troubleshooting my devices in my test environment and digging through old issues on this repository. Had it thrown an error indicating that the URL provided was unreachable or not working, I would had spotted it faster.

STEPS TO REPRODUCE

Environment:

$ ansible --version
ansible 2.9.1
  config file =REDACTED/ansible.cfg
  configured module search path = ['/home/REDACTED/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.6/dist-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 3.6.8 (default, Oct  9 2019, 14:04:01) [GCC 5.4.0 20160609]

$ python --version
Python 3.6.8
---
- name: test playbook
  hosts: "{{ host_group }}"
  gather_facts: yes
  collections:
    - netbox_community.ansible_modules
  vars:
     nb_url: http://localhost:8080
     nb_token: token_goes_here
  tasks:
  - name: Remove default interfaces for each system if present
    netbox_interface:
      netbox_url: nb_url #<- Note this is not wrapped in quotes and curly brackets
      netbox_token: nb_token
      data:
        device: "{{ inventory_hostname }}"
        name: "{{ ansible_default_ipv4.interface }}"
      state: absent
      validate_certs: no
    delegate_to: localhost
EXPECTED RESULTS
TASK [Remove default interfaces for each system if present] ************************************
fatal: [lab-VM-host -> localhost]: FAILED! => changed=false
  msg: 'Cannot reach URL: nb_url'
ACTUAL RESULTS
$ ansible-playbook test_playbook.yaml --extra-vars "host_group=lab-VM-host"
PLAY [test playbook] ************************************

TASK [Remove default interfaces for each system if present]************************************ 
fatal: [lab-VM-host -> localhost]: FAILED! => changed=false
  msg: 'Multiple results found while searching for key: device'

PLAY RECAP ************************************
lab-VM-host : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

remove constants, use the _choices api instead..

ISSUE TYPE
  • Feature Idea
SUMMARY

Replace the pre-defined constants in netbox_utils.py, for example:

IP_ADDRESS_STATUS
IP_ADDRESS_ROLE
RACK_TYPE
INTF_FORM_FACTOR
INTF_MODE

by using the _choices api.

ie, to get all the choices from dcim, you an do:

http://api-url/api/dcim/_choices (or using pynetbox - dcim_choicse = nb.dcim.choices())

and it will give all the choices.

This is need because netbox-2.7 replaces many of the numeric constants with "slugs"/human readable values, and in netbox-2.8, the numeric constants will no longer be honored..

If you use the _choices api, you will also maintain compatibility with netbox-2.6 (since it also supports the choices api)

lag in netbox_interface searches through all devices, not just current one

SUMMARY

Specifying lag for the netbox_interface searches through the all devices instead of specific one.

netbox_interface:
  data:
    device: foo
    lag: bond0

will try to resolve bond0 into the ID, however it will fail since it searches through all interfaces in Netbox. There is a code in build_query_params() to handle this case correctly, but lag option is a string and not dictionary. Changing it to dictionary of course helps since it triggers different codepath, but this leads to the duplication of the device information like following:

netbox_interface:
  data:
    device: foo
    lag:
      device: foo
      name: bond0
ISSUE TYPE
  • Bug Report
COMPONENT NAME

netbox_ip_address or module_utils/net_tools/netbox/netbox_utils.py

ANSIBLE VERSION
ansible 2.9.4
  config file = /home/brain/Projects/gooddata/ansible/ansible.cfg
  configured module search path = ['/home/brain/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.8/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.8.1 (default, Dec 19 2019, 00:00:00) [GCC 9.2.1 20190827 (Red Hat 9.2.1-1)]
CONFIGURATION
ANSIBLE_PIPELINING(/home/brain/Projects/gooddata/ansible/ansible.cfg) = True
DEFAULT_FORKS(/home/brain/Projects/gooddata/ansible/ansible.cfg) = 32
DEFAULT_ROLES_PATH(/home/brain/Projects/gooddata/ansible/ansible.cfg) = ['/home/brain/Projects/gooddata/ansible/roles']
DEFAULT_VAULT_IDENTITY(/home/brain/Projects/gooddata/ansible/ansible.cfg) = cloud
OS / ENVIRONMENT

Fedora 32 (Rawhide). Ansible from repos.

STEPS TO REPRODUCE
- hosts: compute
  gather_facts: no
  tasks:
  - netbox_device:
      data:
        name: "{{ inventory_hostname }}"
        device_type: Gen10
        device_role: Compute
    delegate_to: localhost
  - netbox_interface:
      data:
        device: "{{ inventory_hostname }}"
        name: bond0
        form_factor: Link Aggregation Group (LAG)
    delegate_to: localhost
  - netbox_interface:
      data:
        device: "{{ inventory_hostname }}"
        name: eth0
        form_factor: SFP28 (25GE)
        lag: bond0
    delegate_to: localhost
EXPECTED RESULTS

Code is trying to find bond0 LAG only for the device the netbox_interface operates.

ACTUAL RESULTS
failed: [cmp0009.int.na1.pcigdc.com -> localhost] (item=p4p1) => {"ansible_job_id": "913767063681.40139", "ansible_loop_var": "item", "changed": false, "finished": 1, "item": "p4p1", "msg": "Multiple results found while searching for key: lag"}

Originally reported as ansible/ansible#66955, but reproducible with this ansible-galaxy collection.

Feature: add Device and VM Interface information

ISSUE TYPE
  • Feature Idea
SUMMARY

Implement a new extractor method which includes the inventory information if requested. Additionally, make a second request to gather all device/vm IP addresses and attach them as a list to the interface object.

Original Ansible Core Issues/PR:
ansible/ansible#55982

@mkeetman, since you submitted the original PR that has yet to be merged into core and we've pulled the inventory out of core and into this collection, could you submit a new PR to this Issue?

netbox_device_type: slug is required

ISSUE TYPE
  • Bug Report
SUMMARY

The slug is used in regions, sites and more places, and is not mandatory there. However, for netbox_device_type, it seems to be mandatory. It does not seem that it is necessary since other netbox ansible modules are generating it automatically.

Add All Virtualization Modules

ISSUE TYPE
  • Feature Idea
SUMMARY
  • cluster-types
  • cluster-groups
  • clusters
  • virtual-machines
  • interfaces

I believe there is a PR for a few of these, I will move them from Ansible PR into modules here and credit the author of the modules and then create the remaining

Netbox lookup plugin should support filters

ISSUE TYPE
  • Feature Idea
SUMMARY

At present, the Netbox lookup plugin only supports returning all objects from Netbox for a given endpoint. This is inefficient and will most likely require the user to subsequently filter the returned data set in Ansible using something like jmespath (which brings it's own problems).

The Netbox API (and hence the pynetbox module) supports a feature rich way to filter the results and this should be exposed through the netbox lookup module.

STEPS TO REPRODUCE
  - name: Return details for device R1-Device
    debug:
      msg: "{{ query('fragmentedpacket.netbox_modules.netbox', 'devices', api_endpoint='http://localhost:32776', token='0123456789abcdef0123456789abcdef01234567', filter='name=`R1-Device`') }}"
EXPECTED RESULTS
ok: [localhost] => {
    "msg": [
        {
            "key": 3, 
            "value": {
                "asset_tag": null, 
                "cluster": null, 
                "comments": "", 
                "config_context": {}, 
                "created": "2019-10-17", 
                "custom_fields": {}, 
                "device_role": {
                    "id": 1, 
                    "name": "Core Switch", 
                    "slug": "core-switch", 
                    "url": "http://localhost:32776/api/dcim/device-roles/1/"
                }, 
                "device_type": {
                    "display_name": "Cisco Cisco Test", 
                    "id": 1, 
                    "manufacturer": {
                        "id": 1, 
                        "name": "Cisco", 
                        "slug": "cisco", 
                        "url": "http://localhost:32776/api/dcim/manufacturers/1/"
                    }, 
                    "model": "Cisco Test", 
                    "slug": "cisco-test", 
                    "url": "http://localhost:32776/api/dcim/device-types/1/"
                }, 
                "display_name": "R1-Device", 
                "face": null, 
                "id": 3, 
                "last_updated": "2019-10-17T22:24:01.544233Z", 
                "local_context_data": null, 
                "name": "R1-Device", 
                "parent_device": null, 
                "platform": null, 
                "position": null, 
                "primary_ip": null, 
                "primary_ip4": null, 
                "primary_ip6": null, 
                "rack": null, 
                "serial": "", 
                "site": {
                    "id": 1, 
                    "name": "Test Site", 
                    "slug": "test-site", 
                    "url": "http://localhost:32776/api/dcim/sites/1/"
                }, 
                "status": {
                    "label": "Active", 
                    "value": 1
                }, 
                "tags": [], 
                "tenant": null, 
                "vc_position": null, 
                "vc_priority": null, 
                "virtual_chassis": null
            }
        }
    ]
}
ACTUAL RESULTS

filter='' is currently ignored and, by virtue of the all() method being called, all "devices" are currently returned.

Look into adding argument specs for data key

ISSUE TYPE
  • Feature Idea
SUMMARY

Need to look into argument spec to validate the data passed in via the data dictionary. Last time I messed with it, it was provided default values and updating Netbox endpoints that it shouldn't have been.

Module failure when set status VM to offline

ISSUE TYPE
  • Bug Report
SUMMARY

Module failure when set status VM to online

STEPS TO REPRODUCE

You can create play with module netbox_virtual_machine and try set status any exist VM in NetBox to one (online) and note this issue. When status of VM in play set to zero (offline) module work as expected.

    - name: Ensure that status of VMs within Netbox set correct (active)
      netbox_virtual_machine:
        netbox_url: "{{ nb_url }}"
        netbox_token: "{{ nb_token }}"
        data:
          name: "{{ item.guest_name }}"
          cluster: "{{ item.cluster }}"
          status: 1
        validate_certs: no
      loop: "{{ vm_summary_info['virtual_machines'] }}"
      when: item.power_state == 'poweredOn'

EXPECTED RESULTS

Status of VM in netbox is Active

ACTUAL RESULTS
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: AttributeError: 'int' object has no attribute 'lower'
failed: [localhost] (item={'guest_name': 'nsxmgr.vmware.net.vmw', 'guest_fullname': 'Other Linux (64-bit)', 'power_state': 'poweredOn', 'ip_address': '192.168.100.240', 'mac_address': ['00:50:56:a1:06:3e'], 'uuid': '023e2142-ba46-e83b-f12e-6ebf22f80414', 'vm_network': {'00:50:56:a1:06:3e': {'ipv4': ['192.168.100.240'], 'ipv6': []}}, 'esxi_hostname': 'esxi-mgmt-2.vmware.net.vmw', 'cluster': 'MGMT-CLU', 'attributes': {}, 'tags': []}) => {"ansible_loop_var": "item", "changed": false, "item": {"attributes": {}, "cluster": "MGMT-CLU", "esxi_hostname": "esxi-mgmt-2.vmware.net.vmw", "guest_fullname": "Other Linux (64-bit)", "guest_name": "nsxmgr.vmware.net.vmw", "ip_address": "192.168.100.240", "mac_address": ["00:50:56:a1:06:3e"], "power_state": "poweredOn", "tags": [], "uuid": "023e2142-ba46-e83b-f12e-6ebf22f80414", "vm_network": {"00:50:56:a1:06:3e": {"ipv4": ["192.168.100.240"], "ipv6": []}}}, "module_stderr": "Traceback (most recent call last):\n  File \"/home/ruslan/.ansible/tmp/ansible-tmp-1575660013.973549-41569775518392/AnsiballZ_netbox_virtual_machine.py\", line 102, in <module>\n    _ansiballz_main()\n  File \"/home/ruslan/.ansible/tmp/ansible-tmp-1575660013.973549-41569775518392/AnsiballZ_netbox_virtual_machine.py\", line 94, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/home/ruslan/.ansible/tmp/ansible-tmp-1575660013.973549-41569775518392/AnsiballZ_netbox_virtual_machine.py\", line 40, in invoke_module\n    runpy.run_module(mod_name='ansible_collections.fragmentedpacket.netbox_modules.plugins.modules.netbox_virtual_machine', init_globals=None, run_name='__main__', alter_sys=False)\n  File \"/usr/lib/python3.6/runpy.py\", line 208, in run_module\n    return _run_code(code, {}, init_globals, run_name, mod_spec)\n  File \"/usr/lib/python3.6/runpy.py\", line 85, in _run_code\n    exec(code, run_globals)\n  File \"/tmp/ansible_netbox_virtual_machine_payload_sos_97sv/ansible_netbox_virtual_machine_payload.zip/ansible_collections/fragmentedpacket/netbox_modules/plugins/modules/netbox_virtual_machine.py\", line 191, in <module>\n  File \"/tmp/ansible_netbox_virtual_machine_payload_sos_97sv/ansible_netbox_virtual_machine_payload.zip/ansible_collections/fragmentedpacket/netbox_modules/plugins/modules/netbox_virtual_machine.py\", line 186, in main\n  File \"/tmp/ansible_netbox_virtual_machine_payload_sos_97sv/ansible_netbox_virtual_machine_payload.zip/ansible_collections/fragmentedpacket/netbox_modules/plugins/module_utils/netbox_virtualization.py\", line 31, in __init__\n  File \"/tmp/ansible_netbox_virtual_machine_payload_sos_97sv/ansible_netbox_virtual_machine_payload.zip/ansible_collections/fragmentedpacket/netbox_modules/plugins/module_utils/netbox_utils.py\", line 428, in __init__\n  File \"/tmp/ansible_netbox_virtual_machine_payload_sos_97sv/ansible_netbox_virtual_machine_payload.zip/ansible_collections/fragmentedpacket/netbox_modules/plugins/module_utils/netbox_utils.py\", line 548, in _change_choices_id\nAttributeError: 'int' object has no attribute 'lower'\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

Idempotency is broken if vid is declared as a string

ISSUE TYPE
  • Bug Report
SUMMARY

When a vid is declared with a string as its vid, the vlan is correctly created in netbox but idempotency is broken.
before will be int and after will be string so changed will always be true.

This is also the case for other modules.

STEPS TO REPRODUCE
- name: "netbox add vlans"
  netbox_community.ansible_modules.netbox_vlan:
    netbox_token: "{{ netbox['token'] }}"
    netbox_url: "{{ netbox['url'] }}"
    validate_certs: "no"
    data:
      status: "Active"
      vid: "{{ item['vlanid'] }}"
      name: "{{ item['name'] }}"
      site: "{{ item['location'] }}"
  connection: local
  delegate_to: localhost
  loop: "{{ subnet|flatten(levels=1) }}"
 - vlanid: "42"
  name: "vlaname"
  location: "xxx"
EXPECTED RESULTS
    "ansible_loop_var": "item",
    "changed": false,
    "diff": {
        "after": {},
        "before": {}
    },
ACTUAL RESULTS
    "ansible_loop_var": "item",
    "changed": true,
    "diff": {
        "after": {
            "vid": "42"
        },
        "before": {
            "vid": 42
        }
    },

Can not assign ip-address to virtual-machine

ISSUE TYPE
  • Module question
SUMMARY

Can not assign ip-address to virtual-machine interface.

STEPS TO REPRODUCE

You can create following play to test behavior:

    - name: assign ip to vm
      netbox_ip_address:
        netbox_url: "{{ nb_url }}"
        netbox_token: "{{ nb_token }}"
        data:
          interface:
            name: ens38
            virtual_machine: "{{ vm_name }}"
          address: 10.20.30.40/24
        validate_certs: no
EXPECTED RESULTS

I expect that ip-address 10.20.30.40 will assign to virtual-machine interface 'ens38' with ip-address 10.20.30.40/24. How I can to do this?

ACTUAL RESULTS

The task failed:

TASK [assign ip to vm] ****************************************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "module_stderr": "/home/ruslan/.local/lib/python3.6/site-packages/urllib3/connectionpool.py:1004: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings\n  InsecureRequestWarning,\n/home/ruslan/.local/lib/python3.6/site-packages/urllib3/connectionpool.py:1004: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings\n  InsecureRequestWarning,\nTraceback (most recent call last):\n  File \"/home/ruslan/.ansible/tmp/ansible-tmp-1575373869.351383-49768338133248/AnsiballZ_netbox_ip_address.py\", line 102, in <module>\n    _ansiballz_main()\n  File \"/home/ruslan/.ansible/tmp/ansible-tmp-1575373869.351383-49768338133248/AnsiballZ_netbox_ip_address.py\", line 94, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/home/ruslan/.ansible/tmp/ansible-tmp-1575373869.351383-49768338133248/AnsiballZ_netbox_ip_address.py\", line 40, in invoke_module\n    runpy.run_module(mod_name='ansible_collections.fragmentedpacket.netbox_modules.plugins.modules.netbox_ip_address', init_globals=None, run_name='__main__', alter_sys=False)\n  File \"/usr/lib/python3.6/runpy.py\", line 208, in run_module\n    return _run_code(code, {}, init_globals, run_name, mod_spec)\n  File \"/usr/lib/python3.6/runpy.py\", line 85, in _run_code\n    exec(code, run_globals)\n  File \"/tmp/ansible_netbox_ip_address_payload_mejfduo7/ansible_netbox_ip_address_payload.zip/ansible_collections/fragmentedpacket/netbox_modules/plugins/modules/netbox_ip_address.py\", line 262, in <module>\n  File \"/tmp/ansible_netbox_ip_address_payload_mejfduo7/ansible_netbox_ip_address_payload.zip/ansible_collections/fragmentedpacket/netbox_modules/plugins/modules/netbox_ip_address.py\", line 257, in main\n  File \"/tmp/ansible_netbox_ip_address_payload_mejfduo7/ansible_netbox_ip_address_payload.zip/ansible_collections/fragmentedpacket/netbox_modules/plugins/module_utils/netbox_ipam.py\", line 39, in __init__\n  File \"/tmp/ansible_netbox_ip_address_payload_mejfduo7/ansible_netbox_ip_address_payload.zip/ansible_collections/fragmentedpacket/netbox_modules/plugins/module_utils/netbox_utils.py\", line 428, in __init__\n  File \"/tmp/ansible_netbox_ip_address_payload_mejfduo7/ansible_netbox_ip_address_payload.zip/ansible_collections/fragmentedpacket/netbox_modules/plugins/module_utils/netbox_utils.py\", line 582, in _find_ids\n  File \"/home/ruslan/.local/lib/python3.6/site-packages/pynetbox/core/endpoint.py\", line 135, in get\n    filter_lookup = self.filter(**kwargs)\n  File \"/home/ruslan/.local/lib/python3.6/site-packages/pynetbox/core/endpoint.py\", line 220, in filter\n    ret = [self._response_loader(i) for i in req.get()]\n  File \"/home/ruslan/.local/lib/python3.6/site-packages/pynetbox/core/query.py\", line 239, in get\n    return req_all(self.url)\n  File \"/home/ruslan/.local/lib/python3.6/site-packages/pynetbox/core/query.py\", line 217, in req_all\n    req = make_request(url)\n  File \"/home/ruslan/.local/lib/python3.6/site-packages/pynetbox/core/query.py\", line 214, in make_request\n    raise RequestError(req)\npynetbox.core.query.RequestError: The request failed with code 500 Internal Server Error but more specific details were not returned in json. Check the NetBox Logs or investigate this exception's error attribute.\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

PLAY RECAP ****************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

Feature: add region to query_filter options

ISSUE TYPE
  • Feature Idea
SUMMARY

Add region to ALLOWED_DEVICE_QUERY_PARAMETERS in the inventory plugin.

STEPS TO REPRODUCE

I'd like to be able to apply a query filter of "region", to provide a way to select devices across a subset of sites but without specifying them all individually.

e.g.:

query_filters:

  • region: launchsites

rather than:

query_filters:

  • site: moon
  • site: earth
  • site: mars
  • site: neptune
EXPECTED RESULTS

If I add "region" to the list ALLOWED_DEVICE_QUERY_PARAMETERS in /plugins/inventory/netbox.py it works as I'd hoped.

ACTUAL RESULTS

Currently I get this:

[WARNING]: Warning: region not in ('asset_tag', 'cluster_id', 'device_type_id', 'has_primary_ip', 'is_console_server', 'is_full_depth', 'is_network_device', 'is_pdu', 'mac_address',
'manufacturer', 'manufacturer_id', 'model', 'name', 'platform', 'platform_id', 'position', 'rack_group_id', 'rack_id', 'role', 'role_id', 'serial', 'site', 'site_id', 'status', 'tag',
'tenant', 'tenant_id', 'virtual_chassis_id') or starting with cf (Custom field)

Feature: support for Custom Field choices

ISSUE TYPE
  • Feature Idea
SUMMARY

When creating a filter for a custom field from type selection it would be great to use the label instead of the ID.

Original Ansible Core Issues:
ansible/ansible#59581

EXPECTED RESULTS

I would expect when query for a custom field i could use the label field instead the ID.

plugin: netbox
api_endpoint: http://netbox.domain.tld
query_filters:
  - cf_system_stage: dev

The Netbox API does support this, when the /api/extras/_custom_field_choices/ has been used, see also Netbox issue #1792

Add primary_ip4/6 to netbox_ip_address

ISSUE TYPE
  • Bug Report
SUMMARY

Add primary_ip4/6 to netbox_ip_address module (works if specified, but not documented)
Will need to add logic as well to dynamically determine ID of specified primary_ip4/6

Bug: Netbox Inventory group_by returns space separated groups

ISSUE TYPE
  • Bug Report
SUMMARY

When instructing the NetBox inventory to group by device roles, the inventory uses the role's name, which contains spaces.

Original Ansible Core Issues:
ansible/ansible#53380
ansible/ansible#53384

@nikkytub since you've started a PR to use the roles slug, could you expand that to the other group_by values and submit a PR to this issue? We've pulled the inventory plugin out of core and into this collection for faster updates.

STEPS TO REPRODUCE

The inventory file looks like the following:

plugin: netbox
api_endpoint: <endpoint>
validate_certs: no
token: <token>
query_filters:
  - name: QA-DE-1-ASR11a
group_by:
  - sites
  - device_roles

After an ansible-inventory --list, I expect grouped results by site and role.

EXPECTED RESULTS
{
  "all": {
        "children": [
            "device_roles_neutron-router",
            "sites_QA-DE-1a",
            "ungrouped"
        ]
    },
    "device_roles_neutron-router": {
        "hosts": [
            "QA-DE-1-ASR11a"
        ]
    },
    "sites_QA-DE-1a": {
        "hosts": [
            "QA-DE-1-ASR11a"
        ]
    }
}

I would expect the inventory to use the role-slug from netbox or the replace the spaces in the role's name by underscores.

ACTUAL RESULTS
{
    "all": {
        "children": [
            "device_roles_Neutron Router",
            "sites_QA-DE-1a",
            "ungrouped"
        ]
    },
    "device_roles_Neutron Router": {
        "hosts": [
            "QA-DE-1-ASR11a"
        ]
    },
    "sites_QA-DE-1a": {
        "hosts": [
            "QA-DE-1-ASR11a"
        ]
    }
}

Add CHANGELOG.md

ISSUE TYPE
  • Documentation update
SUMMARY

Need to add a CHANGELOG.md to track changes between releases moving forward
Will add this before 0.1.0 release into Ansible Collections

Updating of vm_interfaces fails

ISSUE TYPE
  • Bug Report
SUMMARY

Creating interfaces for VMs generates an error when the interface name is already taken by an other VM

STEPS TO REPRODUCE

Create to VMs within Netbox and assign the interface ens192 to the VMs
Try to update the MAC Adress for the VMs with the following task:

- name: Create interface
  fragmentedpacket.netbox_modules.netbox_vm_interface:
    netbox_url:  "{{ netbox_url }}"
    netbox_token:  "{{ netbox_token }}"
    data:
      virtual_machine: "{{ inventory_hostname }}"
      name: "{{ ansible_default_ipv4.interface }}"
      mac_address: "{{ ansible_default_ipv4.macaddress }}"
      mtu: 1500
      enabled: true
  delegate_to: localhost
  become: false
EXPECTED RESULTS

Update the already existing interface

ACTUAL RESULTS
The full traceback is:
  File "/tmp/ansible_fragmentedpacket.netbox_modules.netbox_vm_interface_payload_ycs6qc_9/ansible_fragmentedpacket.netbox_modules.netbox_vm_interface_payload.zip/ansible_collections/fragmentedpacket/netbox_modules/plugins/module_utils/netbox_virtualization.py", line 71, in run
    self.nb_object = nb_endpoint.get(**object_query_params)
  File "/home/user/python3/ansible_2.9/lib/python3.7/site-packages/pynetbox/core/endpoint.py", line 141, in get
    "get() returned more than one result. "

fatal: [pll0400-ipam001.domain.loc -> localhost]: FAILED! => {
    "changed": false,
    "invocation": {
        "module_args": {
            "data": {
                "enabled": true,
                "mtu": 1500,
                "name": "foo",
                "virtual_machine": 160
            },
            "netbox_token": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "netbox_url": "http://pll0400-ipam001.domain.loc",
            "state": "present",
            "validate_certs": true
        }
    },
    "msg": "More than one result returned for foo"
}


netbox_ip_address is not idempotent

ISSUE TYPE
  • Bug Report
SUMMARY
    - name: Assign the IP address based on inventory
      netbox_ip_address:
        netbox_url: "{{ netbox_url }}"
        netbox_token: "{{ netbox_token }}"
        data:
          interface:
            name: bond0
            device: "{{ device }}"
          address: "{{ item.value }}"
          dns_name: "{{ inventory_hostname_short }}.{{ item.key }}.{{ domain }}"
          description: "DNS zone: {{ item.key }}.{{ domain }}"
          status: Active
        state: present
      loop: "{{ ips | dict2items }}"
      async: 30
      poll: 1
      delegate_to: localhost

for some reason is not idempotent, this was not the case with ansible's core netbox_ip_address.

STEPS TO REPRODUCE
# -e netbox_token=<token> -e netbox_url=<url>
---
- hosts: compute
  gather_facts: false
  strategy: free
  collections:
    - netbox_community.ansible_modules
  tasks:
    - name: Set device name to use further
      set_fact: device={{ inventory_hostname_short }}.{{ domain }}
    - name: Create a device
      netbox_device:
        netbox_url: "{{ netbox_url }}"
        netbox_token: "{{ netbox_token }}"
        data:
          name: "{{ device }}"
          site: "{{ dc }}"
          status: Active
          device_type: ProLiant DL380 Gen10
          device_role: Compute
        state: present
      delegate_to: localhost
    - name: Create bond0
      netbox_interface:
        netbox_url: "{{ netbox_url }}"
        netbox_token: "{{ netbox_token }}"
        data:
          device: "{{ device }}"
          name: bond0
          form_factor: Link Aggregation Group (LAG)
          enabled: yes
      delegate_to: localhost
    - name: Create physical interfaces under bond0
      netbox_interface:
        netbox_url: "{{ netbox_url }}"
        netbox_token: "{{ netbox_token }}"
        data:
          device: "{{ device }}"
          name: "{{ item }}"
          form_factor: SFP28 (25GE)
          # XXX: https://github.com/ansible/ansible/issues/66955
          lag:
            device: "{{ device }}"
            name: bond0
          mode: Tagged
          tagged_vlans:
            - name: ext
              site: "{{ dc }}"
            - name: int
              site: "{{ dc }}"
          enabled: yes
      loop:
        - em5
        - p4p1
      async: 30
      poll: 1
      delegate_to: localhost
    - name: Assign the IP address based on inventory
      netbox_ip_address:
        netbox_url: "{{ netbox_url }}"
        netbox_token: "{{ netbox_token }}"
        data:
          interface:
            name: bond0
            device: "{{ device }}"
          address: "{{ item.value }}"
          dns_name: "{{ inventory_hostname_short }}.{{ item.key }}.{{ domain }}"
          description: "DNS zone: {{ item.key }}.{{ domain }}"
          status: Active
        state: present
      loop: "{{ ips | dict2items }}"
      async: 30
      poll: 1
      delegate_to: localhost
PLAY [compute] *********************************************************************************************************************************************************************

TASK [Set device name to use further] **********************************************************************************************************************************************
ok: [cmp0037.int.na1.pcigdc.com]

TASK [Create a device] *************************************************************************************************************************************************************
ok: [cmp0037.int.na1.pcigdc.com -> localhost]

TASK [Create bond0] ****************************************************************************************************************************************************************
ok: [cmp0037.int.na1.pcigdc.com -> localhost]

TASK [Create physical interfaces under bond0] **************************************************************************************************************************************
ok: [cmp0037.int.na1.pcigdc.com -> localhost] => (item=em5)
ok: [cmp0037.int.na1.pcigdc.com -> localhost] => (item=p4p1)

TASK [Assign the IP address based on inventory] ************************************************************************************************************************************
changed: [cmp0037.int.na1.pcigdc.com -> localhost] => (item={'key': 'ipmi', 'value': '10.12.0.135'})
changed: [cmp0037.int.na1.pcigdc.com -> localhost] => (item={'key': 'int', 'value': '10.12.48.135'})
changed: [cmp0037.int.na1.pcigdc.com -> localhost] => (item={'key': 'ext', 'value': '10.12.16.135'})

PLAY RECAP *************************************************************************************************************************************************************************
cmp0037.int.na1.pcigdc.com : ok=5    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
EXPECTED RESULTS

Running playbook multiple times will show ok=6 changed=0

ACTUAL RESULTS

Running playbook multiple times shows ok=5 changed=1


Sorry for not minimal playbook example, since I had it written already and it was working fine with ansible's core version of netbox_ip_address.

Licensing issues

Hello,

the LICENSE and galaxy.yml says MIT, but the note on top of the code says GPL-3.0+...

Which one is correct? Also, I would appreciate if you could fix this and publish new version to a galaxy.

interface and assign it to parent LAG] error

ISSUE TYPE
  • Bug Report
SUMMARY
STEPS TO REPRODUCE
      netbox_device_interface:
        netbox_url: "http://localhost:32775"
        netbox_token: "64d95bd488a66f3b745ed175df8d0ce089af5b0b"
        data:
          device: test100
          name: GigabitEthernet1
          enabled: false
          form_factor: 1000Base-t (1GE)
          lag:
            name: port-channel1
          mtu: 1600
          mgmt_only: false
          mode: Access
        state: present
EXPECTED RESULTS
PLAY RECAP *************************************************************************************
localhost   : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
ACTUAL RESULTS
TASK [Create interface and assign it to parent LAG] ****************************************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "msg": "{\"type\":[\"Select a valid choice. 200 is not one of the available choices.\"]}"}
Ansible -vvv results
ansible-playbook 2.9.5
  config file = None
  configured module search path = ['/Users/mtlocus/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.7/site-packages/ansible
  executable location = /usr/local/bin/ansible-playbook
  python version = 3.7.3 (default, Mar 27 2019, 09:23:15) [Clang 10.0.1 (clang-1001.0.46.3)]
No config file found; using defaults
host_list declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
Skipping due to inventory source not existing or not being readable by the current user
script declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
auto declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
Skipping due to inventory source not existing or not being readable by the current user
yaml declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
Skipping due to inventory source not existing or not being readable by the current user
ini declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
Skipping due to inventory source not existing or not being readable by the current user
toml declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAYBOOK: test1.yml ************************************************************************************************************************************************************
1 plays in test1.yml

PLAY [Test Netbox modules] *****************************************************************************************************************************************************
META: ran handlers

TASK [Create interface and assign it to parent LAG] ****************************************************************************************************************************
task path: /Users/mtlocus/devnet/git/ansible_modules/tests/integration/test1.yml:9
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: mtlocus
<127.0.0.1> EXEC /bin/sh -c 'echo ~mtlocus && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /Users/mtlocus/.ansible/tmp/ansible-tmp-1582210756.625417-86552937312337 `" && echo ansible-tmp-1582210756.625417-86552937312337="` echo /Users/mtlocus/.ansible/tmp/ansible-tmp-1582210756.625417-86552937312337 `" ) && sleep 0'
Using module file /Users/mtlocus/.ansible/collections/ansible_collections/netbox_community/ansible_modules/plugins/modules/netbox_device_interface.py
<127.0.0.1> PUT /Users/mtlocus/.ansible/tmp/ansible-local-36370grvis7ap/tmpct3ct4si TO /Users/mtlocus/.ansible/tmp/ansible-tmp-1582210756.625417-86552937312337/AnsiballZ_netbox_device_interface.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /Users/mtlocus/.ansible/tmp/ansible-tmp-1582210756.625417-86552937312337/ /Users/mtlocus/.ansible/tmp/ansible-tmp-1582210756.625417-86552937312337/AnsiballZ_netbox_device_interface.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/usr/local/opt/python/bin/python3.7 /Users/mtlocus/.ansible/tmp/ansible-tmp-1582210756.625417-86552937312337/AnsiballZ_netbox_device_interface.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /Users/mtlocus/.ansible/tmp/ansible-tmp-1582210756.625417-86552937312337/ > /dev/null 2>&1 && sleep 0'
The full traceback is:
  File "/var/folders/rv/3qvskvh554n0dc38n7zjczx80000gp/T/ansible_netbox_device_interface_payload_ywsypkfn/ansible_netbox_device_interface_payload.zip/ansible_collections/netbox_community/ansible_modules/plugins/module_utils/netbox_utils.py", line 355, in _nb_endpoint_get
    response = nb_endpoint.get(**query_params)
  File "/usr/local/lib/python3.7/site-packages/pynetbox/core/endpoint.py", line 138, in get
    filter_lookup = self.filter(**kwargs)
  File "/usr/local/lib/python3.7/site-packages/pynetbox/core/endpoint.py", line 225, in filter
    ret = [self._response_loader(i) for i in req.get()]
  File "/usr/local/lib/python3.7/site-packages/pynetbox/core/query.py", line 300, in get
    return req_all()
  File "/usr/local/lib/python3.7/site-packages/pynetbox/core/query.py", line 279, in req_all
    req = self._make_call(add_params=add_params)
  File "/usr/local/lib/python3.7/site-packages/pynetbox/core/query.py", line 263, in _make_call
    raise RequestError(req)
fatal: [localhost]: FAILED! => {
    "changed": false,
    "invocation": {
        "module_args": {
            "data": {
                "description": null,
                "device": "test100",
                "enabled": false,
                "form_factor": "1000Base-t (1GE)",
                "lag": {
                    "name": "port-channel1"
                },
                "mac_address": null,
                "mgmt_only": false,
                "mode": "Access",
                "mtu": 1600,
                "name": "GigabitEthernet1",
                "tagged_vlans": null,
                "tags": null,
                "untagged_vlan": null
            },
            "netbox_token": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "netbox_url": "http://localhost:32775",
            "state": "present",
            "validate_certs": true
        }
    },
    "msg": "{\"type\":[\"Select a valid choice. 200 is not one of the available choices.\"]}"
}

PLAY RECAP *********************************************************************************************************************************************************************
localhost                  : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

Finish Most IPAM Modules

ISSUE TYPE
  • New Module
SUMMARY

Have PR in for RIRs and need the following to finish off IPAM modules:

  • aggregates
  • services

Bug: Invalid query parameters applied to VM API

ISSUE TYPE
  • Bug Report
SUMMARY

When using the query_filters option and the serial filter, all virtual machines are returned due to serial not being a valid query filter (or field) for virtual machines. Netbox ignores invalid query parameters and returns all results matching the other (if any) filters.

The offending line is here:
https://github.com/netbox-community/ansible_modules/blob/devel/plugins/inventory/netbox.py#L418

Some additional parsing of query parameters is needed to remove anything invalid for virtual-machines.

Original Ansible Core Issues:
ansible/ansible#57376

@tyler-8 was the original reporter.

STEPS TO REPRODUCE
  • Add device with serial number ABC1234 to Netbox
  • Add VM to netbox
# netbox_inventory.yml
plugin: netbox
api_endpoint: http://localhost:8000
validate_certs: True
config_context: False
group_by:
  - device_roles
query_filters:
  - serial: ABC1234
EXPECTED RESULTS

One device returned in inventory

ACTUAL RESULTS

One device and one VM returned in inventory

Add several new modules and related tests

ISSUE TYPE
  • Feature Idea
SUMMARY

Add several new modules:
netbox_platform
netbox_device_type
netbox_manufacturer
netbox_rack
netbox_rack_group
netbox_rack_role
netbox_ipam_roles
netbox_vrf
netbox_vlan
netbox_vlan_group

Bug: netbox_prefix: Invalid vlan_group key for vlan filter

Hello,

I have a VLAN with the same ID in two different VLAN Groups.
Trying to create a prefix with mapping to this VLAN results in the following error:

Traceback:
The full traceback is:
Traceback (most recent call last):
File "/root/.ansible/tmp/ansible-tmp-1581424930.1219447-139266201143184/AnsiballZ_netbox_prefix.py", line 102, in
_ansiballz_main()
File "/root/.ansible/tmp/ansible-tmp-1581424930.1219447-139266201143184/AnsiballZ_netbox_prefix.py", line 94, in _ansiballz_main
invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
File "/root/.ansible/tmp/ansible-tmp-1581424930.1219447-139266201143184/AnsiballZ_netbox_prefix.py", line 40, in invoke_module
runpy.run_module(mod_name='ansible_collections.fragmentedpacket.netbox_modules.plugins.modules.netbox_prefix', init_globals=None, run_name='main', alter_sys=True)
File "/usr/lib/python3.7/runpy.py", line 205, in run_module
return _run_module_code(code, init_globals, run_name, mod_spec)
File "/usr/lib/python3.7/runpy.py", line 96, in _run_module_code
mod_name, mod_spec, pkg_name, script_name)
File "/usr/lib/python3.7/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/tmp/ansible_netbox_prefix_payload_3dyfcsgu/ansible_netbox_prefix_payload.zip/ansible_collections/fragmentedpacket/netbox_modules/plugins/modules/netbox_prefix.py", line 269, in
File "/tmp/ansible_netbox_prefix_payload_3dyfcsgu/ansible_netbox_prefix_payload.zip/ansible_collections/fragmentedpacket/netbox_modules/plugins/modules/netbox_prefix.py", line 264, in main
File "/tmp/ansible_netbox_prefix_payload_3dyfcsgu/ansible_netbox_prefix_payload.zip/ansible_collections/fragmentedpacket/netbox_modules/plugins/module_utils/netbox_ipam.py", line 39, in init
File "/tmp/ansible_netbox_prefix_payload_3dyfcsgu/ansible_netbox_prefix_payload.zip/ansible_collections/fragmentedpacket/netbox_modules/plugins/module_utils/netbox_utils.py", line 430, in init
File "/tmp/ansible_netbox_prefix_payload_3dyfcsgu/ansible_netbox_prefix_payload.zip/ansible_collections/fragmentedpacket/netbox_modules/plugins/module_utils/netbox_utils.py", line 601, in _find_ids
File "/usr/local/lib/python3.7/dist-packages/pynetbox/core/endpoint.py", line 142, in get
"get() returned more than one result. "
ValueError: get() returned more than one result. Check that the kwarg(s) passed are valid for this endpoint or use filter() or all() instead.

Module arguments:
tasks:
- name: Create prefix within Netbox with only required information
netbox_prefix:
netbox_url: http://192.168.56.101:32774/
netbox_token: 0123456789abcdef0123456789abcdef01234567
data:
prefix: 10.156.0.0/19
site: US2
prefix_role: services
vlan:
name: vlan10
vlan_group: vgroup1
site: US2
state: present

At ngnix side it looks like
netbox_1 | 172.19.0.7 - - [10/Feb/2020:01:30:26 +0000] "GET /api/ipam/vlans/?name=vlan10&site_id=1&vlan_group_id=1 HTTP/1.0" 200 1012 "-" "python-requests/2.21.0"

For some reasons it uses vlan_group_id=1 instead of group_id=1.

I can see _convert_identical_keys function for pynetbox but it looks like this error is triggered somewhere earlier in module.

New Module: RIR

ISSUE TYPE
  • New Module
SUMMARY

Add a Netbox module to create/update/delete RIRs

Cant use "." symbols in site name

ISSUE TYPE
  • Bug Report
  • Feature Idea
SUMMARY

Cant use "." symbols in site name

STEPS TO REPRODUCE
- name: "Create Site"
  connection: local
  hosts: localhost
  collections:
   - netbox_community.ansible_modules
  gather_facts: False
  tasks:
    - name: Create site within Netbox with only required information
      netbox_site:
        netbox_url: "{{ url }}"
        netbox_token: "{{ token }}"
        data:
          name: test-1.one.two.org
          tenant: VPC
        state: present
EXPECTED RESULTS

expected slug is test_1_one_two_org

ACTUAL RESULTS

Got an error

But have message:
`"msg": "{\"slug\":[\"Enter a valid \\\"slug\\\" consisting of letters, numbers, underscores or hyphens.\"]}",`

To fix this bug:

def _to_slug(self, value):
        """
        :returns slug (str): Slugified value
        :params value (str): Value that needs to be changed to slug format
        """
        if value is None:
            return value
        elif isinstance(value, int):
            return value
        if " " in value:
            value = value.replace(" ", "_")
        if "." in value:
            value = value.replace(".", "_")
        value = value.lower()

Add A Few DCIM modules

ISSUE TYPE
  • Feature Idea
SUMMARY

Finish off most DCIM modules

  • regions
  • device-bays
  • inventory-items
  • virtual-chassis (may need to update netbox_device to tie to virtual-chassis)

There are several DCIM remaining, but will let others contribute those if they have the use case:

  • rack-reservations (low priority)
  • console-port-templates (low priority)
  • console-server-port-templates (low priority)
  • power-port-templates (low priority)
  • power-outlet-templates (low priority)
  • interface-templates (low priority)
  • front-port-templates (low priority)
  • rear-port-templates (low priority)
  • device-bay-templates (low priority)
  • console-ports (low priority)
  • console-server-ports (low priority)
  • power-ports (low priority)
  • power-outlets (low priority)
  • front-ports (low priority)
  • rear-ports (low priority)
  • console-connections (low priority)
  • power-connections (low priority)
  • interface-connections (low priority)
  • cables (low priority)
  • power-panels (low priority)
  • power-feeds (low priority)
  • connected-device (low priority)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.