Skip to content

Commit

Permalink
finished synchring device EoX data
Browse files Browse the repository at this point in the history
  • Loading branch information
Reimann, Timo committed Sep 21, 2021
1 parent 95be7d4 commit 14da2fb
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 24 deletions.
1 change: 1 addition & 0 deletions netbox_cisco_support/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class CiscoSupportAdmin(admin.ModelAdmin):
class CiscoSupportAdmin(admin.ModelAdmin):
list_display = (
"device",
"is_covered",
"coverage_end_date",
"warranty_end_date"
)
128 changes: 106 additions & 22 deletions netbox_cisco_support/management/commands/sync_eox_data.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from develop.configuration import CISCO_CLIENT_ID, CISCO_CLIENT_SECRET
from pprint import pprint
import requests
import json
import django.utils.text
Expand All @@ -8,7 +9,7 @@
from requests import api
from dcim.models import Manufacturer
from dcim.models import Device, DeviceType
from netbox_cisco_support.models import CiscoDeviceTypeSupport
from netbox_cisco_support.models import CiscoDeviceTypeSupport, CiscoSupport


class Command(BaseCommand):
Expand All @@ -23,6 +24,58 @@ def add_arguments(self, parser):
help='Manufacturer name (default: Cisco)',
)

def update_device_eox_data(self, device):
self.stdout.write(self.style.SUCCESS("Trying to update device %s" % device['sr_no']))

d = Device.objects.get(serial=device['sr_no'])

try:
ds = CiscoSupport.objects.get(device=d)
except CiscoSupport.DoesNotExist:
ds = CiscoSupport(device=d)

value_changed = False

covered = True if device['is_covered'] == "YES" else False

self.stdout.write(self.style.SUCCESS("%s - covered: %s" % (device['sr_no'], covered)))
if ds.is_covered != covered:
ds.is_covered = covered
value_changed = True

try:
if not device['warranty_end_date']:
self.stdout.write(self.style.NOTICE("%s has no warranty_end_date" % device['sr_no']))
else:
warranty_end_date_string = device['warranty_end_date']
warranty_end_date = datetime.strptime(warranty_end_date_string, '%Y-%m-%d').date()
self.stdout.write(self.style.SUCCESS("%s - warranty_end_date: %s" % (device['sr_no'], warranty_end_date)))

if ds.warranty_end_date != warranty_end_date:
ds.warranty_end_date = warranty_end_date
value_changed = True
except KeyError:
self.stdout.write(self.style.NOTICE("%s has no warranty_end_date" % device['sr_no']))

try:
if not device['covered_product_line_end_date']:
self.stdout.write(self.style.NOTICE("%s has no covered_product_line_end_date" % device['sr_no']))
else:
coverage_end_date_string = device['covered_product_line_end_date']
coverage_end_date = datetime.strptime(coverage_end_date_string, '%Y-%m-%d').date()
self.stdout.write(self.style.SUCCESS("%s - coverage_end_date: %s" % (device['sr_no'], coverage_end_date)))

if ds.coverage_end_date != coverage_end_date:
ds.coverage_end_date = coverage_end_date
value_changed = True
except KeyError:
self.stdout.write(self.style.NOTICE("%s has no coverage_end_date" % device['sr_no']))

if value_changed:
ds.save()

return

def update_device_type_eox_data(self, pid, eox_data):
# Get the device type object for the supplied PID
dt = DeviceType.objects.get(part_number=pid)
Expand Down Expand Up @@ -51,6 +104,7 @@ def update_device_type_eox_data(self, pid, eox_data):
if dts.end_of_sale_date != end_of_sale_date:
dts.end_of_sale_date = end_of_sale_date
value_changed = True

# Do nothing when JSON field does not exist
except KeyError:
self.stdout.write(self.style.NOTICE("%s has no end_of_sale_date" % pid))
Expand Down Expand Up @@ -162,11 +216,12 @@ def get_device_types(self, manufacturer):
return dt

def get_product_ids(self, manufacturer):
i = 0
product_ids = []

# Get all device types for supplied manufacturer
dt = self.get_device_types(manufacturer)

# Iterate all this device types
for device_type in dt:

# Skip if the device type has no valid part number. Part numbers must match the exact Cisco Base PID
Expand All @@ -180,47 +235,52 @@ def get_product_ids(self, manufacturer):

return product_ids

def get_serial_numbers(self, dtype):
# trying to get all devices and its serial numbers for this device type (for contract data)
try:
d = Device.objects.filter(device_type=dtype)
def get_serial_numbers(self, manufacturer):
serial_numbers = []

# Get all device types for supplied manufacturer
dt = self.get_device_types(manufacturer)

for device in d:
# Iterate all this device types
for device_type in dt:
# trying to get all devices and its serial numbers for this device type (for contract data)
try:
d = Device.objects.filter(device_type=device_type)

# Skip if the device has no valid serial number.
if not device.serial:
self.stdout.write(self.style.WARNING('Found device "%s" WITHOUT Serial Number - SKIPPING' % (device)))
continue
for device in d:
# Skip if the device has no valid serial number.
if not device.serial:
self.stdout.write(self.style.WARNING('Found device "%s" WITHOUT Serial Number - SKIPPING' % (device)))
continue

# TODO - Add serial number to a list and do something with it rather than displaying.
self.stdout.write(self.style.SUCCESS('Found device "%s" with Serial Number "%s"' % (device, device.serial)))
except Device.DoesNotExist:
raise CommandError('Device with device type "%s" does not exist' % dtype)
return
# TODO - Add serial number to a list and do something with it rather than displaying.
self.stdout.write(self.style.SUCCESS('Found device "%s" with Serial Number "%s"' % (device, device.serial)))
serial_numbers.append(device.serial)
except Device.DoesNotExist:
raise CommandError('Device with device type "%s" does not exist' % dt)

return serial_numbers

def logon(self):
token_url = "https://cloudsso.cisco.com/as/token.oauth2"
data = {'grant_type': 'client_credentials', 'client_id': CISCO_CLIENT_ID, 'client_secret': CISCO_CLIENT_SECRET}

access_token_response = requests.post(token_url, data=data)
# self.stdout.write(self.style.NOTICE(access_token_response.text))

tokens = json.loads(access_token_response.text)
# self.stdout.write(self.style.NOTICE("access token: %s" % tokens['access_token'])

api_call_headers = {'Authorization': 'Bearer ' + tokens['access_token'], 'Accept': 'application/json'}

return api_call_headers

def handle(self, *args, **kwargs):
product_ids = self.get_product_ids(kwargs['manufacturer'])
api_call_headers = self.logon()

"""
product_ids = self.get_product_ids(kwargs['manufacturer'])
self.stdout.write(self.style.SUCCESS('Gathering data for these PIDs: ' + ', '.join(product_ids)))
api_call_headers = self.logon()

i = 1

for pid in product_ids:
# if i == 10:
# break
Expand All @@ -240,4 +300,28 @@ def handle(self, *args, **kwargs):
self.update_device_type_eox_data(pid, data)
i += 1
"""

serial_numbers = self.get_serial_numbers(kwargs['manufacturer'])
self.stdout.write(self.style.SUCCESS('Gathering data for these Serial Numbers: ' + ', '.join(serial_numbers)))

i = 1
while serial_numbers:
# Pop the first items_to_fetch items of serial_numbers into current_slice and then delete them from serial
# numbers. We want to pass x items to the API each time we call it
items_to_fetch = 10
current_slice = serial_numbers[:items_to_fetch]
serial_numbers[:items_to_fetch] = []

url = 'https://api.cisco.com/sn2info/v2/coverage/summary/serial_numbers/%s' % ','.join(current_slice)
api_call_response = requests.get(url, headers=api_call_headers)
self.stdout.write(self.style.SUCCESS('Call ' + url))

data = json.loads(api_call_response.text)

for device in data['serial_numbers']:
# print("Serial: %s - Is Covered?: %s - Warranty End Date: %s - Covered Product Line End Date: %s" % (device['sr_no'], device['is_covered'], device['warranty_end_date'], device['covered_product_line_end_date']))
self.update_device_eox_data(device)

i += 1
23 changes: 23 additions & 0 deletions netbox_cisco_support/migrations/0006_auto_20210921_0941.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 3.2.6 on 2021-09-21 09:41

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('netbox_cisco_support', '0005_auto_20210914_1344'),
]

operations = [
migrations.AlterField(
model_name='ciscosupport',
name='coverage_end_date',
field=models.DateField(blank=True, null=True),
),
migrations.AlterField(
model_name='ciscosupport',
name='warranty_end_date',
field=models.DateField(blank=True, null=True),
),
]
10 changes: 8 additions & 2 deletions netbox_cisco_support/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,15 @@ def __str__(self):
return "%s Support" % self.device

coverage_end_date = models.DateField(
help_text='End date of the contract coverage for the specifed serial number'
help_text='End date of the contract coverage for the specifed serial number',
blank=True,
null=True
)

warranty_end_date = models.DateField(help_text='End date of the warranty for the specified serial number')
warranty_end_date = models.DateField(
help_text='End date of the warranty for the specified serial number',
blank=True,
null=True
)

is_covered = models.BooleanField(help_text='Indicates whether the specified serial number is covered by a service contract', default=False)

0 comments on commit 14da2fb

Please sign in to comment.