/[marcuscom]/meraki/setup_meraki_nets.py
ViewVC logotype

Annotation of /meraki/setup_meraki_nets.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 20565 - (hide annotations) (download) (as text)
Sun Aug 5 18:47:11 2018 UTC (20 months ago) by jclarke
File MIME type: text/x-python
File size: 13144 byte(s)
Update dev_obj after it is claimed.

This is needed to make sure the location can be set properly.

1 jclarke 20550 #!/usr/bin/env python
2     #
3     # Copyright (c) 2018 Joe Clarke <jclarke@cisco.com>
4     #
5     # Redistribution and use in source and binary forms, with or without
6     # modification, are permitted provided that the following conditions
7     # are met:
8     # 1. Redistributions of source code must retain the above copyright
9     # notice, this list of conditions and the following disclaimer.
10     # 2. Redistributions in binary form must reproduce the above copyright
11     # notice, this list of conditions and the following disclaimer in the
12     # documentation and/or other materials provided with the distribution.
13     #
14     # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15     # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16     # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17     # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18     # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19     # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20     # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21     # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22     # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23     # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24     # SUCH DAMAGE.
25    
26    
27     import meraki_api
28     import yaml
29     import argparse
30     import sys
31     import os
32    
33    
34     def main():
35     parser = argparse.ArgumentParser(
36     prog=sys.argv[0], description='Add devices to network')
37     parser.add_argument('--config', '-c', metavar='<CONFIG FILE>',
38     help='Path to the organization configuration file', required=True)
39     parser.add_argument(
40     '--networks', '-n', metavar='<NETWORK>[,<NETWORK>[,...]]', help='Comma-separated list of networks to process')
41     args = parser.parse_args()
42    
43     if not os.path.isfile(args.config):
44     print('Config file {} does not exist or is not a file!'.format(args.config))
45     sys.exit(1)
46    
47     with open(args.config, 'r') as c:
48     config = yaml.load(c)
49    
50     for key in ['api_key', 'organization', 'networks']:
51     if not key in config:
52     print('Invalid config: {} is missing!'.format(key))
53     sys.exit(1)
54    
55     meraki = meraki_api.Meraki(key=config['api_key'])
56     orgs = meraki.get_organizations()
57     org = None
58     for o in orgs:
59     if o.get('name') == config['organization']:
60     org = o
61     break
62    
63     if org is None:
64     print('Failed to find organization {} in this profile!'.format(
65     config['organization']))
66     sys.exit(1)
67    
68     nets = org.get_networks()
69     inv = org.get_inventory()
70    
71     errors = 0
72    
73     configure_nets = None
74     if args.networks is not None:
75     configure_nets = args.networks.split(',')
76    
77     for net in config['networks']:
78     nerrors = 0
79     net_obj = None
80     nname = net.keys()[0]
81     if configure_nets is not None and nname not in configure_nets:
82     continue
83    
84     validn = True
85     for key in ['address', 'timezone']:
86     if key not in net[nname]:
87     print('Invalid network config for {}: {} is missing!'.format(nname, key))
88     errors += 1
89     validn = False
90     break
91    
92     if not validn:
93     continue
94    
95     for n in nets:
96     if n.get('name') == nname:
97     net_obj = n
98     break
99    
100     if net_obj is None:
101 jclarke 20556 nargs = {
102     'timezone': net[nname]['timezone']
103     }
104     if 'copy_from_network' in net[nname]:
105     for n in nets:
106     if n.get('name') == net[nname]['copy_from_network']:
107     nargs['copy_from_network_id'] = n.get('id')
108     break
109 jclarke 20550 net_obj = org.create_network(
110 jclarke 20556 nname, **nargs)
111 jclarke 20550
112     if net_obj is None:
113     print('Error creating new network {}!'.format(nname))
114     errors += 1
115     continue
116    
117 jclarke 20552 if 'devices' in net[nname]:
118     for dev in net[nname]['devices']:
119     serial = dev.keys()[0]
120     if 'name' not in dev[serial]:
121     print('Invalid device {}: name is missing!'.format(serial))
122     nerrors += 1
123     continue
124 jclarke 20550
125 jclarke 20553 inv_dev = filter(
126     lambda device: device['serial'] == serial, inv)
127 jclarke 20552 if len(inv_dev) == 1:
128     dev_obj = None
129     if inv_dev[0]['networkId'] is not None and inv_dev[0]['networkId'] != net_obj.get('id'):
130     try:
131     inv_net_obj = meraki_api.Network(
132     key=config['api_key'], id=inv_dev[0]['networkId'])
133     dev_obj = meraki_api.Device(
134     key=config['api_key'], id=inv_dev[0]['serial'], net=inv_net_obj)
135 jclarke 20550
136 jclarke 20552 res = dev_obj.remove_device()
137     if not res:
138     nerrors += 1
139     continue
140     res = net_obj.claim_device(dev_obj)
141     if not res:
142     nerrors += 1
143     continue
144 jclarke 20565 dev_obj = res
145 jclarke 20552 except Exception as e:
146     print('Error updating device network membership for {}: {}'.format(
147     inv_dev[0]['serial'], e))
148 jclarke 20550 nerrors += 1
149     continue
150 jclarke 20552 elif inv_dev[0]['networkId'] is None:
151     try:
152     dev_obj = meraki_api.Device(
153     key=config['api_key'], id=inv_dev[0]['serial'], net=net_obj)
154     res = net_obj.claim_device(dev_obj)
155     if not res:
156     nerrors += 1
157     continue
158 jclarke 20565 dev_obj = res
159 jclarke 20552 except Exception as e:
160     print('Error claiming device {}: {}'.format(
161     inv_dev[0]['serial'], e))
162 jclarke 20550 nerrors += 1
163     continue
164 jclarke 20552
165     else:
166 jclarke 20550 dev_obj = meraki_api.Device(
167     key=config['api_key'], id=inv_dev[0]['serial'], net=net_obj)
168    
169 jclarke 20552 dev_location = net[nname]['address']
170     dev_name = dev[serial]['name']
171     if 'location' in dev[serial]:
172     dev_location += '\n' + dev[serial]['location']
173     dev_obj.update_device(
174 jclarke 20557 name=dev_name, address=dev_location, move_map_marker=True)
175 jclarke 20552
176 jclarke 20550 else:
177 jclarke 20552 print('Error finding {} in inventory!'.format(serial))
178     nerrors += 1
179 jclarke 20550
180     if 'vlans' in net[nname]:
181     # Ugh. There is no API to enable VLANs yet. So it's best to
182     # make this a manual step. We could interact over the web, but
183     # then we'd need to ask for a real user's credentials.
184 jclarke 20554 #
185 jclarke 20556 # If we copied from an existing network, then we assume that
186     # network has VLANs enabled. If not, this will fail.
187     #
188     if 'copy_from_network' not in net[nname]:
189     print('\n')
190     raw_input(
191     '!!! Enable VLANs for network "{}" manually in the dashboard (under Security appliance > Addressing & VLANs), then hit enter to proceed !!!'.format(nname))
192     print('')
193 jclarke 20550 for vlan in net[nname]['vlans']:
194     vname = vlan.keys()[0]
195     if int(vlan[vname]['id']) != 1:
196     vlan_obj = net_obj.create_vlan(
197     vname, vlan[vname]['id'], vlan[vname]['subnet'], vlan[vname]['appliance_ip'])
198     else:
199     vlan_obj = meraki_api.Vlan(
200     key=config['api_key'], id=1, net=net_obj)
201     if vlan_obj is None:
202     nerrors += 1
203     continue
204     vargs = {}
205     for key in ['reserved_ip_ranges', 'fixed_ip_assignments', 'dns_nameservers']:
206     if key in vlan[vname]:
207     vargs[key] = vlan[vname][key]
208     res = vlan_obj.update_vlan(**vargs)
209     if not res:
210     nerrors += 1
211    
212     if 'ssids' in net[nname]:
213 jclarke 20554 if len(net[nname]['ssids']) > 15:
214     print('Only fifteen SSIDs are allowed per network!')
215 jclarke 20550 nerrors += 1
216     else:
217     si = 0
218     for ssid in net[nname]['ssids']:
219     sname = ssid.keys()[0]
220     ssid_obj = meraki_api.SSID(
221     key=config['api_key'], id=si, name=sname, net=net_obj)
222     sargs = {}
223     for key in ['name', 'enabled', 'auth_mode', 'encryption_mode', 'psk', 'ip_assignment_mode']:
224     if key in ssid[sname]:
225     sargs[key] = ssid[sname][key]
226     res = ssid_obj.update_ssid(**sargs)
227     if not res:
228     nerrors += 1
229     si += 1
230    
231     if 'switches' in net[nname]:
232     for switch in net[nname]['switches']:
233     serial = switch.keys()[0]
234     dev_obj = meraki_api.Device(
235     key=config['api_key'], id=serial, net=net_obj)
236     if not dev_obj.realize():
237     print('Device {} is not in network {}'.format(
238     serial, net_obj.get('name')))
239     nerrors += 1
240     continue
241    
242     for switchport in switch[serial]:
243     port_range = switchport.keys()[0]
244     ports = []
245     if isinstance(port_range, (int, long)):
246     port_obj = meraki_api.SwitchPort(
247     key=config['api_key'], id=port_range, dev=dev_obj)
248     ports.append(port_obj)
249     else:
250     prs = port_range.split(',')
251     for pr in prs:
252     pr = pr.strip()
253     if isinstance(pr, (int, long)):
254     port_obj = meraki_api.SwitchPort(
255     key=config['api_key'], id=pr, dev=dev_obj)
256     ports.append(pr)
257     else:
258     if '-' not in pr:
259     print('Port range {} is invalid.'.format(pr))
260     nerrors += 1
261     continue
262    
263     (start, end) = pr.split('-')
264     start = start.strip()
265     end = end.strip()
266     if not isinstance(start, (int, long)) or not isinstance(end, (int, long)):
267     print('Error with port range {} and {} must be integers'.format(
268     pr, start, end))
269     nerrors += 1
270     continue
271    
272     if start >= end:
273     print(
274     'Error with port range {}; start must be less than end'.format(pr))
275     nerrors += 1
276     continue
277    
278     pi = start
279     while pi <= end:
280     port_obj = meraki_api.SwitchPort(
281     key=config['api_key'], id=pi, dev=dev_obj)
282     ports.append(port_obj)
283     pi += 1
284    
285     for port in ports:
286     pargs = {}
287     for key in ['name', 'tags', 'enabled', 'type', 'vlan', 'voice_vlan', 'allowed_vlans', 'poe_enabled']:
288     if key in switchport[port_range]:
289     pargs[key] = switchport[port_range][key]
290     res = port.update_switchport(**pargs)
291     if not res:
292     nerrors += 1
293    
294     if nerrors == 0:
295     print('Network {} has been setup successfully!'.format(nname))
296     else:
297     print(
298     'Error fully configuring network {}. See the errors above for more details.'.format(nname))
299     errors += nerrors
300    
301     if errors == 0:
302     print('All networks have been setup successfully!')
303     else:
304     print('There were errors setting up some of the networks. See the output above for more details.')
305     sys.exit(1)
306    
307    
308     if __name__ == '__main__':
309     main()

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.27