blob: 8529a3ec1778909e143284141b33fa9a87f21ace [file] [log] [blame]
srikanth116e6e82014-08-19 07:22:37 -07001#
2# Copyright (c) 2013 Big Switch Networks, Inc.
3#
4# Licensed under the Eclipse Public License, Version 1.0 (the
5# "License"); you may not use this file except in compliance with the
6# License. You may obtain a copy of the License at
7#
8# http://www.eclipse.org/legal/epl-v10.html
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13# implied. See the License for the specific language governing
14# permissions and limitations under the License.
15#
16
17from django.db import models
18from django.contrib.auth.models import User
19
20from django.forms import ValidationError
21from django.core.validators import MaxValueValidator
22from sdncon.rest.validators import *
23
24import sys # for sys.maxint
25import time
26
27#
28# controller/models.py
29# ------------------------------------------------------------
30#
31# model description of the tables used to configure and
32# view the controller state.
33#
34# these tables are used both by sdnplatform and the rest api.
35# the cli uses the rest api to read and write these tables,
36# while sdnplatform/sdnplatform has a more direct interface to the
37# tables.
38#
39# for the cli, the names of the fields are described in the
40# 'class Rest' section of each of the tables.
41#
42# for sdnplatform the names of fields have a relationship to their
43# type for sdnplatform. If a field is a foreign key, then an '_id'
44# is appended to the name for the same field within sdnplatform. This
45# means if a field is promoted or demoted to/from a foreign key,
46# changes need to be made in the sdnplatform code to use the updated
47# name.
48#
49# Make sure to include the nested Rest class or else they won't be
50# accessible using the REST API.
51
52#
53#
54# ------------------------------------------------------------
55
56def get_timestamp():
57 """
58 For us in models where the method of ordering the row values
59 is based on the order of creation.
60
61 The field is exposed to the rest api so that the value can
62 be queries, and so that the rest api may choose to order the
63 row values using its own strategy by setting the field directly
64 """
65 return int(time.time()*1000000)
66
srikanth116e6e82014-08-19 07:22:37 -070067#
68# ------------------------------------------------------------
69
70class Feature(models.Model):
71
72 #
73 # fields ----------------------------------------
74
75 id = models.CharField(
76 primary_key=True,
77 verbose_name='feature',
78 default='feature',
79 max_length=16)
80
81 netvirt_feature = models.BooleanField(
82 verbose_name='Network virtualization Feature Enabled',
83 help_text='Enable network virtualization feature by setting to true',
84 default=True
85 )
86
87 static_flow_pusher_feature = models.BooleanField(
88 verbose_name='Static Flow Pusher Feature Enabled',
89 help_text='Enable Static Flow Pusher feature by setting to true',
90 default=True
91 )
92
93 performance_monitor_feature = models.BooleanField(
94 verbose_name='Performance Monitor',
95 help_text="Enable performance monitoring feature by setting to true",
96 default=False
97 )
98
99 #
100 # end fields ----------------------------------------
101
102 def __unicode__(self):
103 return "%s" % (self.id,)
104
105 def validate_unique(self, exclude = None):
106 if self.id != 'feature':
107 raise ValidationError("Only single feature record exists")
108
109 class Rest:
110 NAME = 'feature'
111 FIELD_INFO = (
112 {'name': 'netvirt_feature', 'rest_name': 'netvirt-feature'},
113 {'name': 'static_flow_pusher_feature', 'rest_name': 'static-flow-pusher-feature'},
114 {'name': 'performance_monitor_feature','rest_name': 'performance-monitor-feature'},
115 )
srikanthf2c888b2014-08-20 10:46:55 -0700116"""
srikanth116e6e82014-08-19 07:22:37 -0700117
118#
119# ------------------------------------------------------------
120
121class GlobalConfig(models.Model):
122 #
123 # fields ----------------------------------------
124
125 name = models.CharField(
126 primary_key=True,
127 verbose_name='Global Config Name',
128 help_text="Unique name for the global config; it's a singleton, "
129 "so, by convention, the name should always be \"global\"",
130 default='global',
131 max_length=16)
132
133 cluster_name = models.CharField(
134 verbose_name='Cluster Name',
135 help_text='Name for the cluster',
136 default='SDNCluster',
137 max_length=256)
138
139 cluster_number = models.IntegerField(
140 verbose_name='Cluster Number',
141 help_text='Small integral (1-255) identifier for the cluster',
142 default=0)
143
144 ha_enabled = models.BooleanField(
145 verbose_name='High Availability (HA) Enabled',
146 help_text='Is high availability (HA) enabled',
147 default=False)
148
149 #
150 # end fields ----------------------------------------
151
152 class Rest:
153 NAME = 'global-config'
154 FIELD_INFO = (
155 {'name': 'cluster_name', 'rest_name': 'cluster-name'},
156 {'name': 'cluster_number', 'rest_name': 'cluster-number'},
157 {'name': 'ha_enabled', 'rest_name': 'ha-enabled'},
158 )
159
160#
161# ------------------------------------------------------------
162
163class TopologyConfig(models.Model):
164 #
165 # fields ----------------------------------------
166
167 id = models.CharField(
168 primary_key=True,
169 verbose_name='topology',
170 default='topology',
171 max_length=16)
172
173
174 autoportfast = models.BooleanField(
175 verbose_name='Auto PortFast',
176 help_text='Suppress sending LLDPs on fast ports.',
177 default=True
178 )
179
180 #
181 # end fields ----------------------------------------
182
183 def __unicode__(self):
184 return "%s" % (self.id,)
185
186 def validate_unique(self, exclude = None):
187 if self.id != 'topology':
188 raise ValidationError("Only single topology record exists")
189
190 class Rest:
191 NAME = 'topology-config'
192 FIELD_INFO = (
193 )
194
195
196#
197# ------------------------------------------------------------
198
199class ForwardingConfig(models.Model):
200 #
201 # fields ----------------------------------------
202
203 id = models.CharField(
204 primary_key=True,
205 verbose_name='forwarding',
206 default='forwarding',
207 max_length=16)
208
209 access_priority = models.IntegerField(
210 verbose_name='Access Flow Priority',
211 help_text='Priority for flows created by forwarding on access switches',
212 validators=[ RangeValidator(0,2**15-1) ],
213 default=10)
214
215 core_priority = models.IntegerField(
216 verbose_name='Core Flow Priority',
217 help_text='Priority for flows created by forwarding on core switches',
218 validators=[ RangeValidator(0,2**15-1) ],
219 default=20)
220
221 #
222 # end fields ----------------------------------------
223
224 def __unicode__(self):
225 return "%s" % (self.id,)
226
227 def validate_unique(self, exclude = None):
228 if self.id != 'forwarding':
229 raise ValidationError(
230 "Only a single forwarding configuration record is allowed"
231 )
232
233 class Rest:
234 NAME = 'forwarding-config'
235 FIELD_INFO = (
236 {'name': 'access_priority', 'rest_name': 'access-priority'},
237 {'name': 'core_priority', 'rest_name': 'core-priority'},
238 )
239
srikanthf2c888b2014-08-20 10:46:55 -0700240"""
srikanth116e6e82014-08-19 07:22:37 -0700241#
242# ------------------------------------------------------------
243
244class Controller(models.Model):
245 #
246 # fields ----------------------------------------
247 #
248 # Note: This model should only contain config state for the controller VM,
249 # not any operational state.
250 #
251 # Note: The convention used to be that the controller ID was
252 # the IP address and port that the OpenFlow controller was listening
253 # on. In practice SDNPlatform listened on all interfaces and it's logic
254 # for determining its real IP address was unreliable, so it was
255 # changed/simplified to just always use "localhost" for the
256 # IP address. So the controller ID was pretty much always
257 # "localhost:6633". The use of "controller here caused some
258 # confusion about whether "controller" meant the
259 # OpenFlow controller (i.e. SDNPlatform/SDNPlatform) vs. the controller VM.
260 # In the old controller model most/all of the settings concerned the
261 # OpenFlow controller not the VM>
262 # Most of the settings we now want to associate with the controller are
263 # controller VM settings (e.g. IP address, DNS, time zone) and not
264 # OpenFlow controller settings. So we're repurposing the Controller
265 # model to be the controller VM config state and not the OpenFlow
266 # controller discovered state (which was sort of broken to begin with).
267 # Currently (as of 10/2011), since we only support single node operation
268 # the controller ID is hard-coded to be localhost (probably should be
269 # something different, e.g. "default", because localhost implies a
270 # an interface which is really something separate), but eventually for
271 # multi-node operation we'll need to have unique ids for each controller
272 # node in the cluster. The easiest way would be to have the user enter
273 # something at first time config. Or possibly we could do something
274 # with GUIDs. Needs more thought...
275 id = models.CharField(
276 primary_key=True,
277 verbose_name='Controller ID',
278 help_text='Unique identifier string for the controller node',
279 validators=[ validate_controller_id ],
280 max_length=256)
281
282 status = models.CharField(
283 verbose_name='Status',
284 help_text='cluster status of node',
285 max_length=256,
286 default='Provisioned',
287 )
288
289 domain_lookups_enabled = models.BooleanField(
290 verbose_name='Domain Lookups Enabled',
291 help_text='If domain lookups are enabled (default is True)',
292 default=True
293 )
294
295 domain_name = models.CharField(
296 verbose_name='Domain Name',
297 help_text='Domain name of the network',
298 max_length=256,
299 validators=[ DomainNameValidator() ],
300 default='',
301 blank=True)
302
303 default_gateway = models.CharField(
304 verbose_name='Default Gateway',
305 help_text='Default gateway',
306 max_length=256,
307 validators=[ IpValidator() ],
308 default='',
309 blank=True)
310
311 ntp_server = models.CharField(
312 verbose_name='NTP Server',
313 help_text='NTP server',
314 max_length=256,
315 validators=[ IpOrDomainNameValidator() ],
316 default='',
317 blank=True,
318 null=True)
319
320 time_zone = models.CharField(
321 verbose_name='Time Zone',
322 help_text='Time zone (e.g. America/Los_Angeles)',
323 max_length=256,
324 validators=[ TimeZoneValidator() ],
325 default='UTC')
326
327 logging_enabled = models.BooleanField(
328 verbose_name='Logging Enabled',
329 help_text='Logging enabled',
330 default=False
331 )
332
333 logging_server = models.CharField(
334 verbose_name='Logging Server',
335 help_text='Logging server',
336 max_length=256,
337 validators=[ IpOrDomainNameValidator() ],
338 default='',
339 blank=True,
340 null=True)
341
342 logging_level = models.CharField(
343 verbose_name='Logging Level',
344 help_text='Logging level',
345 max_length=16,
346 validators=[ EnumerationValidator(('emerg', 'alert', 'crit', 'err',
347 'warning', 'notice', 'info', 'debug', '0', '1', '2', '3', '4',
348 '5', '6', '7'))],
349 default='notice'
350 )
351
352 # IOS let's you specify the domain name(s) of the network in two
353 # ways. You can specify a single domain name with the "ip domain name <domain-name>"
354 # command. You can specify multiple domain names with multiple
355 # "ip domain list <domain-name>" commands. The domain names specified with
356 # "ip domain list" commands take precedence over the domain name specified with
357 # the "ip domain name" command, so the single "ip domain name" is only
358 # used if the domain name list is unspecified/empty/null. Kind of messy, but
359 # if we want to emulate IOS behavior I think we'll need to represent that in the
360 # model. But to simplify things for now we'll just support the single domain name.
361
362 #domain_name_list = models.TextField(
363 # verbose_name='Domain Name List',
364 # help_text='List of domain names for the network, one per line',
365 # null=True
366 # )
367
368 #
369 # end fields ----------------------------------------
370
371 def __unicode__(self):
372 return "%s" % (self.id,)
373
374 class Rest:
375 NAME = 'controller-node'
376 FIELD_INFO = (
377 {'name': 'domain_lookups_enabled', 'rest_name': 'domain-lookups-enabled'},
378 {'name': 'domain_name', 'rest_name': 'domain-name'},
379 {'name': 'default_gateway', 'rest_name': 'default-gateway'},
380 {'name': 'ntp_server', 'rest_name': 'ntp-server'},
381 {'name': 'time_zone', 'rest_name': 'time-zone'},
382 {'name': 'logging_enabled', 'rest_name': 'logging-enabled'},
383 {'name': 'logging_server', 'rest_name': 'logging-server'},
384 {'name': 'logging_level', 'rest_name': 'logging-level'},
385 )
386
srikanthf2c888b2014-08-20 10:46:55 -0700387"""
srikanth116e6e82014-08-19 07:22:37 -0700388#
389# ------------------------------------------------------------
390
391class ControllerAlias(models.Model):
392
393 #
394 # fields ----------------------------------------
395
396 alias = models.CharField(
397 primary_key=True,
398 max_length=255,
399 help_text = "alias for controller",
400 verbose_name='alias',
401 validators=[SwitchAliasValidator()])
402
403 controller = models.ForeignKey(
404 Controller,
405 verbose_name='Controller')
406
407 #
408 # end fields ----------------------------------------
409
410 class Rest:
411 NAME = 'controller-alias'
412
413#
414# ------------------------------------------------------------
415
416class ControllerInterface(models.Model):
417
418 #
419 # fields ----------------------------------------
420
421 controller = models.ForeignKey(
422 Controller,
423 verbose_name="Controller ID")
424
425 type = models.CharField(
426 verbose_name='Interface Type',
427 help_text='Type of interface (e.g. "Ethernet")',
428 max_length=256,
429 default='Ethernet'
430 )
431
432 number = models.IntegerField(
433 verbose_name="Interface Number",
434 help_text='Number of interface (non-negative integer)',
435 default=0)
436
437 mode = models.CharField(
438 verbose_name='Mode',
439 help_text='Mode of configuring IP address ("dhcp" or "static")',
440 validators=[ EnumerationValidator(('dhcp', 'static'))],
441 max_length=32,
442 default='static')
443
444 ip = models.CharField(
445 verbose_name='IP Address',
446 help_text='IP Address for interface',
447 validators=[ IpValidator() ],
448 max_length=15,
449 default='',
450 blank=True)
451
452 netmask = models.CharField(
453 verbose_name='Netmask',
454 help_text='Netmask',
455 validators=[ IpValidator() ],
456 max_length=15,
457 default='',
458 blank=True)
459
460 # provide a link between the underlying interface layer
461 # and this model's 'index number' to help manage discovered_ip
462 mac = models.CharField(
463 verbose_name="MAC Address",
464 help_text="MAC Address",
465 max_length=17,
466 validators = [validate_mac_address],
467 blank=True,
468 null=True)
469
470 discovered_ip = models.CharField(
471 verbose_name='Discovered IP Address',
472 help_text='Discovered IP Address for interface',
473 validators=[ IpValidator() ],
474 max_length=15,
475 default='',
476 blank=True)
477
478
479# in_acl = models.ForeignKey(
480# ControllerAcl,
481# verbose_name = 'Controller input acl',
482# blank=True,
483# null=True)
484
485# out_acl = models.ForeignKey(
486# ControllerAcl,
487# verbose_name = 'Controller output acl',
488# blank=True,
489# null=True)
490
491 #
492 # end fields ----------------------------------------
493
494 class CassandraSettings:
495 COMPOUND_KEY_FIELDS = ('controller', 'type', 'number')
496
497 class Rest:
498 NAME = 'controller-interface'
499 FIELD_INFO = (
500 {'name': 'discovered_ip', 'rest_name': 'discovered-ip'},
501# {'name': 'in_acl', 'rest_name': 'in-acl'},
502# {'name': 'out_acl', 'rest_name': 'out-acl'},
503 )
504
505
506#
507# ------------------------------------------------------------
508
509class FirewallRule(models.Model):
510
511 #
512 # fields ----------------------------------------
513
514 interface = models.ForeignKey(
515 ControllerInterface,
516 verbose_name="Controller Interface")
517
518 action = models.CharField(
519 max_length=8,
520 validators=[ EnumerationValidator(('allow', 'deny', 'reject'))],
521 default='allow',
522 blank=True)
523
524 src_ip = models.CharField(
525 verbose_name='Source IP',
526 help_text='IP Address to allow traffic from',
527 validators=[ IpValidator() ],
528 max_length=15,
529 default='',
530 blank=True)
531
532 vrrp_ip = models.CharField(
533 verbose_name='Local IP',
534 help_text='(Local) IP Address to allow traffic to',
535 validators=[ IpValidator() ],
536 max_length=15,
537 default='',
538 blank=True)
539
540 port = models.IntegerField(
541 verbose_name='Port Number',
542 help_text='Port Number',
543 validators=[ RangeValidator(0,2**16-1) ],
544 default=0,
545 blank=True)
546
547 proto = models.CharField(
548 verbose_name="ip proto",
549 help_text="ip protocol (tcp, udp or vrrp)", #TODO validator
550 validators=[ UfwProtocolValditor() ],
551 max_length=4,
552 default='',
553 blank=True)
554
555 #
556 # end fields ----------------------------------------
557
558 class CassandraSettings:
559 COMPOUND_KEY_FIELDS = ('interface', 'src_ip', 'vrrp_ip', 'port', 'proto')
560
561 class Rest:
562 NAME = 'firewall-rule'
563 FIELD_INFO = (
564 {'name': 'src_ip', 'rest_name': 'src-ip'},
565 {'name': 'vrrp_ip', 'rest_name': 'vrrp-ip'},
566 )
567
568#
569# ------------------------------------------------------------
570
571class ControllerDomainNameServer(models.Model):
572
573 controller = models.ForeignKey(
574 Controller,
575 verbose_name="Controller ID",
576 default=None,
577 null=True)
578
579 ip = models.CharField(
580 verbose_name='IP Address',
581 help_text='IP Address of domain name server',
582 validators=[ IpValidator() ],
583 max_length=15,
584 default='')
585
586 timestamp = models.IntegerField(
587 verbose_name='timestamp',
588 help_text='Timestamp to determine order of domain name servers',
589 default = get_timestamp,
590 null=True,
591 blank=True,
592 )
593
594 #
595 # end fields ----------------------------------------
596
597 class CassandraSettings:
598 COMPOUND_KEY_FIELDS = ('controller', 'ip')
599
600 def validate_unique(self, exclude = None):
601 try:
602 exists = ControllerDomainNameServer.objects.get(controller = self.controller,
603 ip = self.ip)
604 if exists.timestamp != self.timestamp:
605 print 'SHAZAM', self.timestamp
606 self.timestamp = exists.timestamp
607 except:
608 pass
609
610 class Rest:
611 NAME = 'controller-domain-name-server'
612 FIELD_INFO = (
613 )
srikanthf2c888b2014-08-20 10:46:55 -0700614"""
srikanth116e6e82014-08-19 07:22:37 -0700615
616#
617# ------------------------------------------------------------
618
619class Switch(models.Model):
620 switch_id_length = 23
621 #
622 # fields ----------------------------------------
623
624 dpid = models.CharField(
625 primary_key=True,
626 verbose_name='Switch DPID',
627 help_text='Switch DPID - 64-bit hex separated by :',
628 max_length=switch_id_length,
629 validators=[ validate_dpid ])
630
631 controller = models.ForeignKey(
632 Controller,
633 verbose_name='Controller ID',
634 blank=True,
635 null=True)
636
637 socket_address = models.CharField(
638 verbose_name='Socket Address',
639 help_text='Socket address used for connection to controller',
640 max_length=64,
641 blank=True,
642 null=True)
643
644 ip = models.CharField(
645 verbose_name='IP Address',
646 help_text='IP Address used for connection from controller',
647 validators=[ IpValidator() ],
648 max_length=15,
649 blank=True,
650 null=True)
651
652 active = models.BooleanField(
653 verbose_name='Active',
654 help_text='Switch is active (i.e. connected to a controller)',
655 default=False)
656
657 connected_since = models.DateTimeField(
658 verbose_name='Last Connect Time',
659 help_text='Time when the switch connected to the controller',
660 blank=True,
661 null=True)
662
663 dp_desc = models.CharField(
664 verbose_name='Description',
665 max_length=256,
666 blank=True,
667 null=True)
668
669 hw_desc = models.CharField(
670 verbose_name='Hardware Description',
671 max_length=256,
672 blank=True,
673 null=True)
674
675 sw_desc = models.CharField(
676 verbose_name='Software Description',
677 max_length=256,
678 blank=True,
679 null=True)
680
681 serial_num = models.CharField(
682 verbose_name='Serial Number',
683 max_length=32,
684 blank=True,
685 null=True)
686
687 capabilities = models.IntegerField(
688 verbose_name='Capabilities',
689 help_text='Openflow switch capabilities',
690 validators=[ RangeValidator(0,2**32-1) ],
691 default=0)
692
693 tunneling_supported = models.BooleanField(
694 default=False,
695 )
696
697 buffers = models.IntegerField(
698 verbose_name='Max Packets',
699 help_text='Maximum number of packets buffered by the switch',
700 validators=[ RangeValidator(0,2**32-1) ],
701 blank=True,
702 null=True)
703
704 tables = models.IntegerField(
705 verbose_name='Max Tables',
706 help_text='Number of tables supported by the switch',
707 validators=[ RangeValidator(0,2**8-1) ],
708 blank=True,
709 null=True)
710
711 actions = models.IntegerField(
712 verbose_name='Actions',
713 help_text='Actions supported by the switch',
714 validators=[ RangeValidator(0,2**32-1) ],
715 default=0)
716
717 #
718 # end fields ----------------------------------------
719
720 # LOOK! we should have an origin field to distinguish
721 # between user-specified switches and 'discovered' switches
722
723 def __unicode__(self):
724 return "%s" % self.dpid
725
726 class Rest:
727 NAME = 'switch'
728 FIELD_INFO = (
729 {'name': 'socket_address', 'rest_name': 'socket-address'},
730 {'name': 'ip', 'rest_name': 'ip-address'},
731 {'name': 'connected_since', 'rest_name': 'connected-since'},
732 {'name': 'dp_desc', 'rest_name': 'dp-desc'},
733 {'name': 'hw_desc', 'rest_name': 'hw-desc'},
734 {'name': 'sw_desc', 'rest_name': 'sw-desc'},
735 {'name': 'serial_num', 'rest_name': 'serial-num'},
736 {'name': 'tunneling_supported', 'rest_name': 'tunnel-supported'},
737 )
738
739#
740# ------------------------------------------------------------
741# SwitchConfig
742# Any 'configured' (non-discovered) state associated with
743# a switch.
744#
745# tunnel_termination; when enabled, tunnels are constructed
746# to any other tunnel_termination switch, building a mesh
747# of open-flow enabled switches. Typicall Used in virtualized
748# environments, where openflow switches are not intended to
749# exist in the path.
750#
751
752class SwitchConfig(models.Model):
753 switch_id_length = 23
754 #
755 # fields ----------------------------------------
756
757 dpid = models.CharField(
758 primary_key=True,
759 verbose_name='Switch DPID',
760 help_text='Switch DPID - 64-bit hex separated by :',
761 max_length=switch_id_length,
762 validators=[ validate_dpid ])
763
764 core_switch = models.BooleanField(
765 default=False,
766 help_text='Identify core switches'
767 )
768
769 tunnel_termination = models.CharField(
770 verbose_name='Tunnel Termination',
771 help_text='Tunnel Termination ("enabled" "disabled" "default")',
772 validators=[ EnumerationValidator(('enabled', 'disabled', 'default'))],
773 default = 'default',
774 max_length=16)
775
776 #
777 # end fields ----------------------------------------
778
779
780 def validate_unique(self, exclude = None):
781 self.dpid = self.dpid.lower()
782
783 class Rest:
784 NAME = 'switch-config'
785 FIELD_INFO = (
786 {'name': 'tunnel_termination', 'rest_name': 'tunnel-termination'},
787 {'name': 'core_switch', 'rest_name': 'core-switch'},
788 )
789
790
791#
792# ------------------------------------------------------------
793
794class SwitchAlias(models.Model):
795
796 #
797 # fields ----------------------------------------
798
799 id = models.CharField(
800 primary_key=True,
801 max_length=255,
802 help_text = "alias for switch",
803 verbose_name='alias',
804 validators=[SwitchAliasValidator()])
805
806 switch = models.ForeignKey(
807 SwitchConfig,
808 verbose_name='Switch DPID')
809
810 #
811 # end fields ----------------------------------------
812
813 class Rest:
814 NAME = 'switch-alias'
815
816
817#
818# ------------------------------------------------------------
819
820class Port(models.Model):
821 #
822 # fields ----------------------------------------
823 #
824 # This table isn't intended to be updated via the rest api,
825 # sdnplatform writes the table to describe a switch.
826 #
827 # The 'number' in the port model is the openflow port number,
828 # which is a value used in setting up flow entries. This is
829 # not an interface name; the 'interface name' is the 'name'
830 # field below. This table provides a mapping from the switch
831 # dpid and port number to an 'interface name'.
832 #
833 # Since interface names can be configured on demand by the
834 # switch, for example to name a tunnel, its not easy to
835 # "guess" interface names without the switch reporting
836 # what interface names exist. This leads to difficulty
837 # in preconfiguring any associations with <switch, interface name>
838 #
839
840 # Unique identifier for the port
841 # combination of the switch DPID and the port number
842 id = models.CharField(
843 primary_key=True,
844 verbose_name='Port ID',
845 help_text = '#|switch|number',
846 max_length=48)
847
848 switch = models.ForeignKey(
849 Switch,
850 verbose_name='Switch DPID')
851
852 number = models.IntegerField(
853 verbose_name='OF #',
854 help_text="Port open flow number",
855 validators=[ RangeValidator(0,2**16-1) ])
856
857 hardware_address = models.CharField(
858 verbose_name="MAC Address",
859 help_text="Port MAC Address",
860 max_length=17,
861 validators = [validate_mac_address],
862 blank=True,
863 null=True)
864
865 name = models.CharField(
866 verbose_name='Name',
867 help_text="Port name",
868 max_length=32,
869 blank=True,
870 null=True)
871
872 config = models.IntegerField(
873 verbose_name='Configuration',
874 help_text='Configuration Flags',
875 validators=[ RangeValidator(0,2**32-1) ],
876 default=0)
877
878 state = models.IntegerField(
879 verbose_name="State",
880 help_text="State Flags",
881 validators=[ RangeValidator(0,2**32-1) ],
882 default=0)
883
884 current_features = models.IntegerField(
885 verbose_name='Current',
886 help_text='Current Features',
887 validators=[ RangeValidator(0,2**32-1) ],
888 default=0)
889
890 advertised_features = models.IntegerField(
891 verbose_name='Advertised',
892 help_text='Advertised Features',
893 validators=[ RangeValidator(0,2**32-1) ],
894 default=0)
895
896 supported_features = models.IntegerField(
897 verbose_name='Supported',
898 help_text='Supported Features',
899 validators=[ RangeValidator(0,2**32-1) ],
900 default=0)
901
902 peer_features = models.IntegerField(
903 verbose_name='Peer',
904 help_text='Peer Features',
905 validators=[ RangeValidator(0,2**32-1) ],
906 default=0)
907
908 #
909 # end fields ----------------------------------------
910
911 def __unicode__(self):
912 return "%s" % (self.id,)
913
914 class Rest:
915 NAME = 'port'
916 FIELD_INFO = (
917 {'name': 'hardware_address', 'rest_name': 'hardware-address'},
918 {'name': 'current_features', 'rest_name': 'current-features'},
919 {'name': 'advertised_features', 'rest_name': 'advertised-features'},
920 {'name': 'supported_features', 'rest_name': 'supported-features'},
921 {'name': 'peer_features', 'rest_name': 'peer-features'},
922 )
923
924#
925# ------------------------------------------------------------
926
927class PortAlias(models.Model):
928
929 #
930 # fields ----------------------------------------
931
932 id = models.CharField(
933 primary_key=True,
934 max_length=255,
935 help_text = "alias for port",
936 verbose_name='alias',
937 validators=[PortAliasValidator()])
938
939 port = models.ForeignKey(
940 Port,
941 help_text = "foreign key for port alias",
942 verbose_name='Port ID')
943
944 #
945 # end fields ----------------------------------------
946
947 class Rest:
948 NAME = 'port-alias'
949#
950# ------------------------------------------------------------
951
952class SwitchInterfaceConfig(models.Model):
953 if_name_len = 32
954 #
955 # fields ----------------------------------------
956
957 switch = models.ForeignKey(
958 SwitchConfig,
959 verbose_name='Switch')
960
961 if_name = models.CharField(
962 verbose_name='If Name',
963 validators=[ SafeForPrimaryKeyValidator() ],
964 max_length=32)
965
966 mode = models.CharField(
967 verbose_name='Mode',
968 help_text='Interface Mode ("external", "default")',
969 validators=[ EnumerationValidator(('external','default'))],
970 max_length=32,
971 default='default')
972
973 broadcast = models.BooleanField(
974 default=False,
975 verbose_name='Broadcast',
976 help_text='True when interfaces is an uplink to a legacy net',
977 )
978
979 #
980 # end fields ----------------------------------------
981
982 def __unicode__(self):
983 return "%s" % (self.id)
984
985 class CassandraSettings:
986 COMPOUND_KEY_FIELDS = ('switch', 'if_name')
987
988 def validate_unique(self, exclude = None):
989 self.broadcast = False
990 if self.mode == 'external':
991 self.broadcast = True
992
993 class Rest:
994 NAME = 'switch-interface-config'
995 FIELD_INFO = (
996 # By using 'name' here, the 'name' from the port is identified
997 # in the complete-from-another procedure
998 {'name': 'if_name', 'rest_name': 'name'},
999 )
1000
1001
1002#
1003# ------------------------------------------------------------
1004
1005class SwitchInterfaceAlias(models.Model):
1006 switch_interface_alias_length = 255
1007 #
1008 # fields ----------------------------------------
1009
1010 id = models.CharField(
1011 primary_key = True,
1012 verbose_name = 'Switch Interface Alias',
1013 help_text = 'alias',
1014 max_length = switch_interface_alias_length,
1015 validators=[HostAliasValidator()])
1016
1017 switch_interface = models.ForeignKey(
1018 SwitchInterfaceConfig,
1019 verbose_name='Switch Interface',
1020 )
1021
1022 #
1023 # end fields ----------------------------------------
1024
1025 class Rest:
1026 NAME = 'switch-interface-alias'
1027 FIELD_INFO = (
1028 {'name': 'switch_interface', 'rest_name': 'switch-interface'},
1029 )
srikanthf2c888b2014-08-20 10:46:55 -07001030"""
srikanth116e6e82014-08-19 07:22:37 -07001031#
1032# ------------------------------------------------------------
1033
1034class StaticFlowTableEntry(models.Model):
1035 #
1036 # fields ----------------------------------------
1037
1038 name = models.CharField(
1039 primary_key=True,
1040 verbose_name='Name',
1041 max_length=80)
1042
1043 switch = models.ForeignKey(
1044 SwitchConfig,
1045 verbose_name="Switch DPID")
1046
1047 active = models.BooleanField(
1048 default=False)
1049
1050 # LOOK! we should hide the timeout values for static flow entry
1051 # definition as they are overwritten (unless we allow these to
1052 # overwrite the default that static flow pusher uses)
1053 idle_timeout = models.IntegerField(
1054 verbose_name="Idle Timeout",
1055 help_text="Expire flow after this many seconds of inactivity - default: 60",
1056 default=60,
1057 validators=[ RangeValidator(0, 2**16-1) ])
1058
1059 hard_timeout = models.IntegerField(
1060 verbose_name="Hard Timeout",
1061 help_text="Seconds to expire flow, regardless of activity - default: 0",
1062 default=0,
1063 validators=[ RangeValidator(0, 2**16-1) ])
1064
1065 priority = models.IntegerField(
1066 verbose_name="Priority",
1067 help_text="Priority of the flow entry",
1068 default=32768,
1069 validators=[ RangeValidator(0, 2**16-1) ])
1070
1071 cookie = models.IntegerField(
1072 verbose_name="Cookie",
1073 default=0) # 64-bit
1074
1075 #
1076 # match fields
1077 #
1078
1079 # LOOK! Need a file of python openflow constants
1080
1081 # LOOK! we should hide this also or at least
1082 # for static flow entries say it is ignored
1083 wildcards = models.IntegerField(
1084 verbose_name="Wildcards",
1085 default=0,
1086 validators=[ RangeValidator(0,2**32-1) ])
1087
1088 in_port = models.IntegerField(
1089 verbose_name="Ingress Port",
1090 blank=True,
1091 help_text="Open flow port number of ingress port",
1092 null=True,
1093 validators = [ RangeValidator(0, 2**16-1) ] )
1094
1095 dl_src = models.CharField(
1096 verbose_name="Src MAC",
1097 help_text="This is a 48-bit quantity specified in xx:xx:xx:xx:xx:xx format",
1098 max_length=17,
1099 blank=True,
1100 null=True,
1101 validators = [ validate_mac_address ] )
1102
1103 dl_dst = models.CharField(
1104 verbose_name="Dst MAC",
1105 help_text="Destination MAC address in the frames",
1106 max_length=17,
1107 blank=True,
1108 null=True,
1109 validators = [ validate_mac_address ] )
1110
1111 dl_vlan = models.IntegerField(
1112 verbose_name="VLAN ID",
1113 help_text="VLAN ID in the frames",
1114 blank=True,
1115 null=True,
1116 validators = [ RangeValidator(0, 2**12-1) ])
1117
1118 dl_vlan_pcp = models.IntegerField(
1119 verbose_name="VLAN Priority",
1120 help_text="VLAN ID in the frames",
1121 blank=True,
1122 null=True,
1123 validators = [ RangeValidator(0, 2**3-1) ])
1124
1125 dl_type = models.IntegerField(
1126 verbose_name="Ether Type",
1127 help_text="Ether(L3) type",
1128 blank=True,
1129 null=True,
1130 validators = [ RangeValidator(0, 2**16-1) ])
1131
1132 nw_tos = models.IntegerField(
1133 verbose_name="TOS Bits",
1134 help_text="TOS bits in the frame",
1135 blank=True,
1136 null=True,
1137 validators = [ RangeValidator(0, 2**6-1) ]) # 6-bit DSCP value
1138
1139 nw_proto = models.IntegerField(
1140 verbose_name="Protocol",
1141 help_text="IP (L4) protocol in the packets",
1142 blank=True,
1143 null=True,
1144 validators = [ RangeValidator(0, 2**8-1) ])
1145
1146 nw_src = models.CharField(
1147 verbose_name="Src IP",
1148 help_text="IP v4 source address in dotted decimal a.b.c.d w/ optional mask (ex: /24)",
1149 max_length=18,
1150 validators = [ CidrValidator(mask_required=False) ],
1151 blank=True,
1152 null=True)
1153
1154 nw_dst = models.CharField(
1155 verbose_name="Dst IP",
1156 help_text="IP v4 destination address in dotted decimal a.b.c.d w/ optional mask (ex: /24)",
1157 validators=[ CidrValidator(mask_required=False) ],
1158 max_length=18,
1159 blank=True,
1160 null=True )
1161
1162 tp_src = models.IntegerField(
1163 verbose_name="Src Port",
1164 help_text="Source (TCP/UDP) port",
1165 blank=True,
1166 null=True,
1167 validators=[ RangeValidator(0, 2**16-1) ])
1168
1169 tp_dst = models.IntegerField(
1170 verbose_name="Dst Port",
1171 help_text="Destination (TCP/UDP) port",
1172 blank=True,
1173 null=True,
1174 validators=[ RangeValidator(0, 2**16-1) ])
1175
1176 # LOOK! have to figure out how to expose actions in the CLI - this is ugly/brittle
1177 actions = models.CharField(
1178 verbose_name = "Actions",
1179 help_text="This is a comma-separated list of actions - a la dpctl",
1180 max_length=1024,
1181 blank=True,
1182 null=True)
1183
1184 #
1185 # end fields ----------------------------------------
1186
1187 def __unicode__(self):
1188 return self.name
1189
1190
1191 class Rest:
1192 NAME = 'flow-entry'
1193 FIELD_INFO = (
1194 {'name': 'idle_timeout', 'rest_name': 'idle-timeout'},
1195 {'name': 'hard_timeout', 'rest_name': 'hard-timeout'},
1196 {'name': 'in_port', 'rest_name': 'ingress-port'},
1197 {'name': 'dl_src', 'rest_name': 'src-mac'},
1198 {'name': 'dl_dst', 'rest_name': 'dst-mac'},
1199 {'name': 'dl_vlan', 'rest_name': 'vlan-id'},
1200 {'name': 'dl_vlan_pcp', 'rest_name': 'vlan-priority'},
1201 {'name': 'dl_type', 'rest_name': 'ether-type'},
1202 {'name': 'nw_tos', 'rest_name': 'tos-bits'},
1203 {'name': 'nw_proto', 'rest_name': 'protocol'},
1204 {'name': 'nw_src', 'rest_name': 'src-ip'},
1205 {'name': 'nw_dst', 'rest_name': 'dst-ip'},
1206 {'name': 'tp_src', 'rest_name': 'src-port'},
1207 {'name': 'tp_dst', 'rest_name': 'dst-port'},
1208 {'name': 'actions', 'rest_name': 'actions'},
1209 )
srikanthf2c888b2014-08-20 10:46:55 -07001210"""
srikanth116e6e82014-08-19 07:22:37 -07001211
1212#
1213# ------------------------------------------------------------
1214
1215class Link(models.Model):
1216 #
1217 # fields ----------------------------------------
1218
1219 id = models.CharField(
1220 primary_key=True,
1221 verbose_name='Link ID',
1222 max_length=64)
1223
1224 src_switch = models.ForeignKey(
1225 Switch,
1226 verbose_name='Src Switch DPID',
1227 related_name='src_link_set')
1228 #src_switch_id = models.CharField(
1229 # verbose_name='Src Switch ID',
1230 # max_length=32)
1231
1232 name = models.CharField(
1233 verbose_name='Name',
1234 help_text="Link name",
1235 max_length=32,
1236 blank=True,
1237 null=True)
1238
1239 src_port = models.IntegerField(
1240 verbose_name="Src Port",
1241 validators=[ RangeValidator(0, 2**16-1) ])
1242
1243 src_port_state = models.IntegerField(
1244 verbose_name="Src Port State",
1245 help_text="Source Port State Flags",
1246 validators=[ RangeValidator(0,2**32-1) ],
1247 default=0)
1248
1249 dst_switch = models.ForeignKey(
1250 Switch,
1251 verbose_name='Dst Switch DPID',
1252 related_name='dst_link_set')
1253 #dst_switch_id = models.CharField(
1254 # verbose_name='Dst Switch ID',
1255 # max_length=32)
1256
1257 dst_port = models.IntegerField(
1258 verbose_name="Dst Port",
1259 help_text="Destination Port",
1260 validators=[ RangeValidator(0, 2**16-1) ])
1261
1262 dst_port_state = models.IntegerField(
1263 verbose_name="Dst Port State",
1264 help_text="Destination Port State Flags",
1265 validators=[ RangeValidator(0,2**32-1) ],
1266 default=0)
1267
1268 link_type = models.CharField(
1269 verbose_name='Link Type',
1270 help_text="Link type",
1271 max_length=10,
1272 blank=True,
1273 null=True)
1274 #
1275 # end fields ----------------------------------------
1276
1277 def __unicode__(self):
1278 return "%s" % self.id
1279
1280 class Rest:
1281 NAME = 'link'
1282 FIELD_INFO = (
1283 {'name': 'src_switch', 'rest_name': 'src-switch'},
1284 {'name': 'src_port', 'rest_name': 'src-port'},
1285 {'name': 'src_port_state', 'rest_name': 'src-port-state'},
1286 {'name': 'dst_switch', 'rest_name': 'dst-switch'},
1287 {'name': 'dst_port', 'rest_name': 'dst-port'},
1288 {'name': 'dst_port_state', 'rest_name': 'dst-port-state'},
1289 {'name': 'link_type', 'rest_name': 'link-type'}
1290 )
1291
srikanthf2c888b2014-08-20 10:46:55 -07001292"""
srikanth116e6e82014-08-19 07:22:37 -07001293#
1294# ------------------------------------------------------------
1295# An address-space separation
1296
1297class AddressSpace (models.Model):
1298
1299 id_max_length = 64
1300
1301 #
1302 # fields ----------------------------------------
1303
1304 #
1305 # Unique name of the address-space
1306 #
1307 name = models.CharField(
1308 primary_key = True,
1309 verbose_name = 'Address Space Name',
1310 help_text = 'A unique name for an Address Space Seperation',
1311 validators = [ AddressSpaceNameValidator() ],
1312 max_length = id_max_length)
1313
1314 #
1315 # Verbose description of this rule.
1316 #
1317 description = models.CharField(
1318 verbose_name = 'Description',
1319 help_text = "Description of the address-space",
1320 max_length = 128,
1321 blank = True,
1322 null = True)
1323
1324 #
1325 # Whether the configuration is active ? By default, it is active
1326 # Used to disable the configuration without having to delete the entire
1327 # address-space configuration construct.
1328 #
1329 active = models.BooleanField(
1330 verbose_name = 'Active',
1331 help_text = 'Is this Address Space active (default is True)',
1332 default = True)
1333
1334 #
1335 # Priority of this address-space during device matching when
1336 # compared to other address-spaces. Those at the same priority
1337 # are used in a determinisitc alphanetical order.
1338 #
1339 priority = models.IntegerField(
1340 verbose_name = 'Priority',
1341 help_text = 'Priority for this Address Space ' +
1342 '(higher numbers are higher priority)',
1343 default = 1000,
1344 validators = [ RangeValidator(0, 65535) ])
1345
1346 #
1347 # Seperator tag of this address-space in the data plane, such as vlan id.
1348 #
1349 vlan_tag_on_egress = models.IntegerField(
1350 verbose_name = 'Egress VLAN tag',
1351 help_text = 'Vlan Tag value used for this Address Space separation',
1352 default = None,
1353 blank = True,
1354 null = True,
1355 validators = [ RangeValidator(0, 4095) ])
1356
1357 #
1358 # Origin of this configured item
1359 #
1360 origin = models.CharField(
1361 verbose_name = "Origin",
1362 help_text = "Values: cli, rest, other packages",
1363 max_length = 64, # in future we might use SW GUIDs for this field
1364 blank = True,
1365 null = True)
1366
1367 #
1368 # end fields ----------------------------------------
1369
1370 def __unicode__ (self):
1371 return self.name
1372
1373 class Rest:
1374 NAME = 'address-space'
1375 FIELD_INFO = (
1376 {'name': 'vlan_tag_on_egress', 'rest_name':'vlan-tag-on-egress'},
1377 )
1378
1379#
1380# ------------------------------------------------------------
1381# An identifier rule in address-space separation
1382
1383class AddressSpaceIdentifierRule (models.Model):
1384 rule_max_length = 32
1385
1386 #
1387 # fields ----------------------------------------
1388
1389 #
1390 # Create a reference to the enclosing address-space construct.
1391 #
1392 address_space = models.ForeignKey(
1393 AddressSpace,
1394 verbose_name = 'Address Space Identifier')
1395
1396 #
1397 # Unique rule identifier name under this address-space.
1398 #
1399 rule = models.CharField(
1400 verbose_name = 'Address Space Rule Identifier',
1401 max_length = rule_max_length)
1402
1403 #
1404 # Verbose description of this rule.
1405 #
1406 description = models.CharField(
1407 verbose_name = 'Description',
1408 help_text = "Description of rule",
1409 max_length = 128,
1410 blank = True,
1411 null = True)
1412
1413 #
1414 # Whether the configuration is active ? By default, it is active
1415 # Used to disable the configuration without having to delete the entire
1416 # address-space identifier-rule configuration construct.
1417 #
1418 active = models.BooleanField(
1419 verbose_name = 'Active',
1420 help_text = 'If this interface is active (default is True)',
1421 default = True)
1422
1423 #
1424 # Priority of this address-space during device matching when
1425 # compared to other address-spaces. Those at the same priority
1426 # are used in a determinisitc alphanetical order.
1427 #
1428 priority = models.IntegerField(
1429 verbose_name = 'Priority',
1430 help_text = 'Priority for this interface rule ' +
1431 '(higher numbers are higher priority)',
1432 default = 32768,
1433 validators = [ RangeValidator(0, 65535) ])
1434
1435 #
1436 # DPID of the Switch which sent the packet
1437 #
1438 switch = models.CharField(
1439 verbose_name = 'Switch DPID',
1440 max_length = Switch.switch_id_length,
1441 help_text = 'Switch DPID or switch alias',
1442 validators = [ validate_dpid ],
1443 null = True,
1444 blank = True)
1445
1446 #
1447 # Range of ports in which the packet came from
1448 #
1449 ports = models.CharField(
1450 verbose_name = "Port Range Spec",
1451 help_text = 'Port range (e.g. C12 or B1,A22-25)',
1452 max_length = 256,
1453 validators = [ PortRangeSpecValidator() ],
1454 blank = True,
1455 null = True)
1456
1457 #
1458 # Range of VLAN tags
1459 #
1460 vlans = models.CharField(
1461 verbose_name = "VLAN Range Spec",
1462 help_text = "VLAN(s) (e.g. 5 or 5-10,4010-4050)",
1463 max_length = 256,
1464 validators = [ VLANRangeSpecValidator() ],
1465 blank = True,
1466 null = True)
1467
1468 #
1469 # NameValue pair of tags
1470 #
1471 tag = models.CharField(
1472 verbose_name = "Tag Spec",
1473 help_text = "Tag values (e.g. namespace.tagname=value)",
1474 max_length = 256,
1475 validators = [ TagSpecValidator() ],
1476 blank = True,
1477 null = True)
1478
1479 #
1480 # end fields ----------------------------------------
1481
1482 def __unicode__ (self):
1483 return self.id
1484
1485 class CassandraSettings:
1486 COMPOUND_KEY_FIELDS = ('address_space', 'rule')
1487
1488 class Rest:
1489 NAME = 'address-space-identifier-rule'
1490 FIELD_INFO = (
1491 {'name': 'description', 'rest_name': 'description'},
1492 {'name': 'address_space', 'rest_name': 'address-space'},
1493 {'name': 'active', 'rest_name': 'active'},
1494 {'name': 'priority', 'rest_name': 'priority'},
1495 {'name': 'switch', 'rest_name': 'switch'},
1496 {'name': 'ports', 'rest_name': 'ports'},
1497 {'name': 'vlans', 'rest_name': 'vlans'},
1498 {'name': 'tag', 'rest_name': 'tag'},
1499 )
srikanthf2c888b2014-08-20 10:46:55 -07001500"""
srikanth116e6e82014-08-19 07:22:37 -07001501#
1502# ------------------------------------------------------------
1503
1504class HostConfig(models.Model):
1505 host_id_length = 17
1506 #
1507 # fields ----------------------------------------
1508
srikanthf2c888b2014-08-20 10:46:55 -07001509 #address_space = models.ForeignKey(
1510 # AddressSpace,
1511 # verbose_name = "Address space name")
srikanth116e6e82014-08-19 07:22:37 -07001512
1513 mac = models.CharField(
1514 verbose_name="MAC Address",
1515 max_length=host_id_length,
1516 validators = [validate_mac_address])
1517
1518 vlan = models.CharField(
1519 verbose_name='VLAN',
1520 help_text='VLAN Associated with host',
1521 max_length=4,
1522 validators=[RangeValidator(1, 4095)],
1523 blank=True,
1524 default='')
1525
1526 #
1527 # end fields ----------------------------------------
1528
1529 def __unicode__(self):
1530 self.mac = self.mac.lower()
srikanthf2c888b2014-08-20 10:46:55 -07001531 #return "%s::%s" % (self.addressSpace, self.mac)
1532 return "%s" % (self.addressSpace)
srikanth116e6e82014-08-19 07:22:37 -07001533
1534 class CassandraSettings:
srikanthf2c888b2014-08-20 10:46:55 -07001535 #COMPOUND_KEY_FIELDS = ('address_space', 'vlan', 'mac')
1536 COMPOUND_KEY_FIELDS = ('vlan', 'mac')
srikanth116e6e82014-08-19 07:22:37 -07001537
1538 def validate_unique(self, exclude = None):
1539 # Invoke the default validator; error out if the vns already exists
1540 super(HostConfig, self).validate_unique(exclude)
srikanthf2c888b2014-08-20 10:46:55 -07001541 #if self.vlan and str(self.address_space) != 'default':
1542 # raise ValidationError('host: vlan configured for '
1543 # 'address-space other than "default" %s' % self.address_space)
srikanth116e6e82014-08-19 07:22:37 -07001544
1545 class Rest:
1546 NAME = 'host-config'
1547 FIELD_INFO = (
srikanthf2c888b2014-08-20 10:46:55 -07001548 #{'name': 'address_space', 'rest_name': 'address-space'},
srikanth116e6e82014-08-19 07:22:37 -07001549 )
1550
1551#
1552# ------------------------------------------------------------
1553
1554class HostSecurityIpAddress(models.Model):
1555 host = models.ForeignKey(
1556 HostConfig,
1557 verbose_name='Host ID')
1558
1559 ip = models.CharField(
1560 verbose_name='IP Address',
1561 help_text='IP Address used to associate with host',
1562 validators=[ IpValidator() ],
1563 max_length=15,
1564 blank=True,
1565 null=True)
1566
1567 #
1568 # end fields ----------------------------------------
1569
1570 def __unicode__(self):
1571 return self.id
1572
1573 class CassandraSettings:
1574 COMPOUND_KEY_FIELDS = ('host', 'ip')
1575
1576 class Rest:
1577 NAME = 'host-security-ip-address'
1578 FIELD_INFO = (
1579 {'name': 'ip', 'rest_name': 'ip-address'},
1580 )
1581
1582
1583#
1584# ------------------------------------------------------------
1585
1586class HostSecurityAttachmentPoint(models.Model):
1587 host = models.ForeignKey(
1588 HostConfig,
1589 verbose_name='Host ID')
1590
1591 dpid = models.CharField(
1592 verbose_name = 'Switch DPID',
1593 max_length = Switch.switch_id_length,
1594 help_text = 'Switch DPID or switch alias',
1595 validators = [ validate_dpid ],
1596 null = True,
1597 blank = True)
1598
1599 if_name_regex = models.CharField(
1600 verbose_name='If Name Regex',
1601 help_text='Interface name regular expression',
1602 max_length=64,
1603 validators = [SafeForPrimaryKeyValidator(), IsRegexValidator()],
1604 blank = True,
1605 null = False,
1606 )
1607
1608
1609 #
1610 # end fields ----------------------------------------
1611
1612 def __unicode__(self):
1613 return self.id
1614
1615 class CassandraSettings:
1616 COMPOUND_KEY_FIELDS = ('host', 'dpid', 'if_name_regex')
1617
1618 class Rest:
1619 NAME = 'host-security-attachment-point'
1620 FIELD_INFO = (
1621 {'name': 'if_name_regex', 'rest_name': 'if-name-regex'},
1622 )
1623
1624#
1625# ------------------------------------------------------------
1626
1627class HostAlias(models.Model):
1628 host_alias_length = 255
1629 #
1630 # fields ----------------------------------------
1631
1632 id = models.CharField(
1633 primary_key = True,
1634 verbose_name = 'Host Alias',
1635 help_text = 'alias',
1636 max_length = host_alias_length,
1637 validators=[HostAliasValidator()])
1638
1639 host = models.ForeignKey(
1640 HostConfig,
1641 verbose_name='Host ID')
1642
1643 #
1644 # end fields ----------------------------------------
1645
1646 class Rest:
1647 NAME = 'host-alias'
1648
srikanthf2c888b2014-08-20 10:46:55 -07001649"""
srikanth116e6e82014-08-19 07:22:37 -07001650class VlanConfig(models.Model):
1651 #
1652 # fields ----------------------------------------
1653 vlan = models.IntegerField(
1654 primary_key = True,
1655 verbose_name='VLAN',
1656 help_text='VLAN Number',
1657 validators=[RangeValidator(0, 4095)],
1658 )
1659
1660 #
1661 # end fields ----------------------------------------
1662
1663 def __unicode__(self):
1664 if self.vlan:
1665 return "%s vlan %s" % (self.vlan)
1666 else:
1667 return "%s vlan %s" % (self.vlan)
1668
1669 class Rest:
1670 NAME = 'vlan-config'
1671
1672#
1673# ------------------------------------------------------------
1674# A Static ARP table separation
1675
1676class StaticArp (models.Model):
1677
1678 id_max_length = 64
1679 #
1680 # fields ----------------------------------------
1681 ip = models.CharField(
1682 primary_key=True,
1683 verbose_name='IP Address',
1684 validators=[ IpValidator() ],
1685 max_length=15)
1686 mac = models.CharField(
1687 verbose_name="MAC Address",
1688 max_length=17,
1689 validators = [validate_mac_address])
1690 #
1691 # Origin of this configured item
1692 #
1693 origin = models.CharField(
1694 verbose_name = "Origin",
1695 help_text = "Values: cli, rest, other packages",
1696 max_length = 64, # in future we might use SW GUIDs for this field
1697 blank = True,
1698 null = True)
1699
1700 #
1701 # end fields ----------------------------------------
1702
1703 def __unicode__ (self):
1704 return self.id
1705
1706 class Rest:
1707 NAME = 'static-arp'
1708
1709
1710
1711#
1712# ------------------------------------------------------------
1713# A Tenant separation
1714
1715class Tenant (models.Model):
1716
1717 id_max_length = 64
1718 #
1719 # fields ----------------------------------------
1720
1721 #
1722 # Unique name of the tenant
1723 #
1724 name = models.CharField(
1725 primary_key = True,
1726 verbose_name = 'Tenant Name',
1727 help_text = 'A unique name for an Tenant',
1728 validators = [ TenantNameValidator() ],
1729 max_length = id_max_length)
1730
1731 #
1732 # Verbose description of this tenant.
1733 #
1734 description = models.CharField(
1735 verbose_name = 'Description',
1736 help_text = "Description of the tenant",
1737 max_length = 128,
1738 blank = True,
1739 null = True)
1740
1741 #
1742 # Whether the configuration is active ? By default, it is active
1743 # Used to disable the configuration without having to delete the entire
1744 # tenant configuration construct.
1745 #
1746 active = models.BooleanField(
1747 verbose_name = 'Active',
1748 help_text = 'Is this Tenant active (default is True)',
1749 default = True)
1750
1751 #
1752 # Origin of this configured item
1753 #
1754 origin = models.CharField(
1755 verbose_name = "Origin",
1756 help_text = "Values: cli, rest, other packages",
1757 max_length = 64, # in future we might use SW GUIDs for this field
1758 blank = True,
1759 null = True)
1760
1761 #
1762 # end fields ----------------------------------------
1763
1764 def __unicode__ (self):
1765 return self.name
1766
1767 def delete(self):
1768 if self.name=='default' or self.name =='system' or self.name =='external':
1769 raise ValidationError("Default/External/System Tenant can't be deleted")
1770 super(Tenant, self).delete()
1771 class Rest:
1772 NAME = 'tenant'
1773
1774
1775#
1776# ------------------------------------------------------------
1777# A virtual router separation
1778
1779class VirtualRouter (models.Model):
1780
1781 id_max_length = 64
1782 #
1783 # fields ----------------------------------------
1784 vrname = models.CharField(
1785 verbose_name = 'Virtual Router Name',
1786 help_text = 'A unique name for a virtual router',
1787 validators = [ GeneralNameValidator() ],
1788 max_length = id_max_length
1789 )
1790
1791 tenant = models.ForeignKey(
1792 Tenant,
1793 verbose_name='Tenant Name',
1794 )
1795 description = models.CharField(
1796 verbose_name = 'Description',
1797 help_text = "Description of the virtual router",
1798 max_length = 128,
1799 blank = True,
1800 null = True,
1801 )
1802
1803 #
1804 # Origin of this configured item
1805 #
1806 origin = models.CharField(
1807 verbose_name = "Origin",
1808 help_text = "Values: cli, rest, other packages",
1809 max_length = 64, # in future we might use SW GUIDs for this field
1810 blank = True,
1811 null = True)
1812
1813 #
1814 # end fields ----------------------------------------
1815
1816 def __unicode__ (self):
1817 return self.id
1818
1819 def validate_unique(self, exclude = None):
1820 # in fat tire, only one router per tenant can be defined. this can be removed later.
1821 error=False
1822 try:
1823 exists = VirtualRouter.objects.get(tenant = self.tenant)
1824 if exists.vrname !=self.vrname:
1825 error=True
1826 except:
1827 pass
1828 if error:
1829 raise ValidationError(" Virtual router %s has been defined for tenant %s, only one virtual router per tenant supported" % (exists.vrname,self.tenant))
1830
1831 class CassandraSettings:
1832 COMPOUND_KEY_FIELDS = ('tenant', 'vrname')
1833
1834 class Rest:
1835 NAME = 'virtualrouter'
1836
1837#
1838# ------------------------------------------------------------
1839# A virtual network segment
1840
1841class VNS(models.Model):
1842 id_max_length = 64
1843 #
1844 # fields ----------------------------------------
1845 vnsname = models.CharField(
1846 verbose_name='VNS ID',
1847 help_text='A unique name for a Virtual Network Segment',
1848 validators=[GeneralNameValidator()],
1849 max_length=id_max_length)
1850 tenant=models.ForeignKey(
1851 Tenant,
1852 verbose_name='Tenant ID',
1853 default='default')
1854 #
1855 # Verbose description of this rule.
1856 #
1857 description = models.CharField(
1858 verbose_name = 'Description',
1859 help_text = "Description of the VNS",
1860 max_length = 128,
1861 blank = True,
1862 null = True)
1863
1864 #
1865 # Reference to the address-space item. By default, we
1866 # implicitly use 'default' if this is not explicitly provided.
1867 #
1868 vns_address_space = models.ForeignKey(
1869 AddressSpace,
1870 verbose_name='Address Space Association',
1871 blank=True,
1872 null=True)
1873
1874 active = models.BooleanField(
1875 verbose_name='Active',
1876 help_text='If this VNS is active (default is True)',
1877 default=True)
1878
1879 priority = models.IntegerField(
1880 verbose_name='Priority',
1881 help_text='Priority for this VNS (higher numbers are higher priority)',
1882 default = 1000,
1883 validators=[RangeValidator(0, 65535)])
1884
1885 origin = models.CharField(
1886 verbose_name = "The origin/creator interface for this VNS",
1887 help_text="Values: cli, rest, other packages",
1888 max_length=64, # in future we might use SW GUIDs for this field
1889 blank=True,
1890 null=True)
1891
1892 arp_mode = models.CharField(
1893 verbose_name = "ARP Manager Config Mode",
1894 help_text="Values: always-flood, flood-if-unknown, drop-if-unknown",
1895 max_length=32,
1896 validators=[VnsArpModeValidator()],
1897 default='flood-if-unknown')
1898
1899 dhcp_mode = models.CharField(
1900 verbose_name = "DHCP Manager Config Mode",
1901 help_text = "Values: always-flood, flood-if-unknown, static",
1902 max_length = 20,
1903 validators=[VnsDhcpModeValidator()],
1904 default='flood-if-unknown')
1905
1906 dhcp_ip = models.CharField(
1907 verbose_name='DHCP IP Address',
1908 help_text='IP Address of DHCP Server',
1909 validators=[ IpValidator() ],
1910 max_length=15,
1911 blank=True,
1912 null=True)
1913
1914 broadcast = models.CharField(
1915 verbose_name = "Broadcast (non ARP/DHCP) Config Mode",
1916 help_text = "Values: always-flood, forward-to-known, drop",
1917 max_length = 20,
1918 validators=[VnsBroadcastModeValidator()],
1919 default='forward-to-known')
1920
1921 #
1922 # end fields ----------------------------------------
1923
1924 def __unicode__(self):
1925 return self.id
1926
1927 def delete(self):
1928 #default VNS can't be deleted
1929 if self.id=='default|default':
1930 raise ValidationError("Default VNS can't be deleted")
1931 #while address space still exist, address space default vns can't be deleted
1932 #for fat tire, relationship between address space and tenant are unclear yet, the following part may need revisit
1933 suffix = '-default'
1934 if self.vnsname.endswith(suffix):
1935 print self.vnsname
1936 address_space_name = self.vnsname[:-len(suffix)]
1937 error=False
1938 try:
1939 self.vns_address_space = AddressSpace.objects.get(name = address_space_name)
1940 error=True
1941 except Exception, e:
1942 pass
1943 if error:
1944 raise ValidationError('vns %s is the default VNS of address space: %s, can not be deleted ' %
1945 (self.vnsname,address_space_name))
1946 super(VNS, self).delete()
1947 # manage a magic association between vns names and
1948 # address space for vns's which end in -default
1949 def validate_unique(self, exclude = None):
1950 # Invoke the default validator; error out if the vns already exists
1951 #for fat tire, relationship between address space and tenant are unclear yet, the following part may need revisit
1952 super(VNS, self).validate_unique(exclude)
1953 suffix = '-default'
1954 if not 'vns_address_space' in exclude:
1955 if self.vns_address_space:
1956 if self.vnsname.endswith(suffix):
1957 if str(self.vns_address_space) != self.vnsname[:-len(suffix)]:
1958 raise ValidationError('vns names %s ending in -default '
1959 'must have address_space names with the same prefix: %s '
1960 % (self.vnsname, self.vns_address_space))
1961 elif self.vnsname.endswith(suffix):
1962 address_space_name = self.vnsname[:-len(suffix)]
1963 try:
1964 self.vns_address_space = AddressSpace.objects.get(name = address_space_name)
1965 except Exception, e:
1966 print e
1967 if self.vns_address_space == None:
1968 raise ValidationError('vns %s has no matching address-space %s ' %
1969 (self.vnsname, address_space_name))
1970
1971 class CassandraSettings:
1972 COMPOUND_KEY_FIELDS = ('tenant', 'vnsname')
1973
1974 class Rest:
1975 NAME = 'vns-definition'
1976 FIELD_INFO = (
1977 {'name': 'vns_address_space', 'rest_name': 'address-space'},
1978 {'name': 'arp_mode', 'rest_name': 'arp-mode'},
1979 {'name': 'dhcp_mode', 'rest_name': 'dhcp-mode'},
1980 {'name': 'dhcp_ip', 'rest_name': 'dhcp-ip'},
1981 )
1982
1983#
1984# ------------------------------------------------------------
1985# An interface rule on a VNS
1986
1987class VNSInterfaceRule(models.Model):
1988 rule_max_length = 32
1989
1990 #
1991 # fields ----------------------------------------
1992
1993 vns = models.ForeignKey(
1994 VNS,
1995 verbose_name='VNS ID')
1996
1997 rule = models.CharField(
1998 verbose_name='VNS Rule ID',
1999 max_length=rule_max_length)
2000
2001 description = models.CharField(
2002 verbose_name='Description',
2003 help_text="Description of rule",
2004 max_length=128,
2005 blank=True,
2006 null=True)
2007
2008 vlan_tag_on_egress = models.BooleanField(
2009 verbose_name='Egress Vlan Tagging',
2010 help_text='Tag with VLAN at egress point (default is False)',
2011 default=False)
2012
2013 allow_multiple = models.BooleanField(
2014 verbose_name='Allow Multiple',
2015 help_text='If this interface allows hosts to be on multiple VNS (default is False)',
2016 default=False)
2017
2018 active = models.BooleanField(
2019 verbose_name='Active',
2020 help_text='If this interface is active (default is True)',
2021 default=True)
2022
2023 priority = models.IntegerField(
2024 verbose_name='Priority',
2025 help_text='Priority for this interface rule (higher numbers are higher priority)',
2026 default = 32768,
2027 validators=[RangeValidator(0, 65535)])
2028
2029 mac = models.CharField(
2030 verbose_name="MAC Address",
2031 help_text='MAC Address or host alias',
2032 max_length=17,
2033 validators = [validate_mac_address],
2034 blank=True,
2035 null=True)
2036
2037 ip_subnet = models.CharField(
2038 verbose_name="IP Subnet",
2039 help_text='IP address or subnet (e.g. 192.168.1.1 or 192.168.1.0/24)',
2040 max_length=31,
2041 validators = [CidrValidator(False)],
2042 blank=True,
2043 null=True)
2044
2045 switch = models.CharField(
2046 verbose_name='Switch DPID',
2047 max_length= Switch.switch_id_length,
2048 help_text='Switch DPID or switch alias',
2049 validators=[ validate_dpid ],
2050 null=True,
2051 blank=True)
2052
2053 ports = models.CharField(
2054 verbose_name="Port Range Spec",
2055 help_text='Port range (e.g. C12 or B1,A22-25)',
2056 max_length=256,
2057 validators = [PortRangeSpecValidator()],
2058 blank=True,
2059 null=True)
2060
2061 vlans = models.CharField(
2062 verbose_name="VLAN Range Spec",
2063 help_text="VLAN(s) (e.g. 5 or 5-10,4010-4050)",
2064 max_length=256,
2065 validators = [VLANRangeSpecValidator()],
2066 blank=True,
2067 null=True)
2068
2069 tags = models.CharField(
2070 verbose_name="Tag Spec",
2071 help_text="Tag values (e.g. namespace.tagname=value)",
2072 max_length=256,
2073 validators = [TagSpecValidator()],
2074 blank=True,
2075 null=True)
2076
2077
2078 #
2079 # end fields ----------------------------------------
2080
2081 def __unicode__(self):
2082 return self.id
2083
2084 class CassandraSettings:
2085 COMPOUND_KEY_FIELDS = ('vns', 'rule')
2086
2087 class Rest:
2088 NAME = 'vns-interface-rule'
2089 FIELD_INFO = (
2090 {'name': 'description', 'rest_name': 'description'},
2091 {'name': 'allow_multiple', 'rest_name': 'allow-multiple'},
2092 {'name': 'active', 'rest_name': 'active'},
2093 {'name': 'priority', 'rest_name': 'priority'},
2094 {'name': 'mac', 'rest_name': 'mac'},
2095 {'name': 'ip_subnet', 'rest_name': 'ip-subnet'},
2096 {'name': 'switch', 'rest_name': 'switch'},
2097 {'name': 'ports', 'rest_name': 'ports'},
2098 {'name': 'vlans', 'rest_name': 'vlans'},
2099 {'name': 'tags', 'rest_name': 'tags'},
2100 {'name': 'vlan_tag_on_egress', 'rest_name': 'vlan-tag-on-egress'},
2101 )
2102
2103#
2104# ------------------------------------------------------------
2105
2106class VNSInterfaceConfig(models.Model):
2107 name_max_length = 32
2108 #
2109 # fields ----------------------------------------
2110
2111 vns = models.ForeignKey(
2112 VNS,
2113 verbose_name='VNS ID')
2114
2115 interface = models.CharField(
2116 verbose_name='VNS Interface Name',
2117 max_length=name_max_length,
2118 validators = [VnsInterfaceNameValidator()])
2119
2120 rule = models.ForeignKey(
2121 VNSInterfaceRule,
2122 verbose_name='VNS Rule ID',
2123 blank=True,
2124 null=True)
2125
2126 #
2127 # end fields ----------------------------------------
2128
2129 def __unicode__(self):
2130 return self.id
2131
2132 class CassandraSettings:
2133 COMPOUND_KEY_FIELDS = ('vns', 'interface')
2134
2135 class Rest:
2136 NAME = 'vns-interface-config'
2137 FIELD_INFO = (
2138 {'name': 'rule', 'rest_name': 'rule'},
2139 )
2140
2141
2142#
2143# ------------------------------------------------------------
2144
2145class VNSAcl(models.Model):
2146 name_max_length=32
2147 #
2148 # fields ----------------------------------------
2149
2150 vns = models.ForeignKey(
2151 VNS,
2152 verbose_name='VNS ID')
2153
2154 name = models.CharField(
2155 help_text='Acl Name',
2156 validators=[VnsAclNameValidator()],
2157 max_length=name_max_length)
2158
2159 priority = models.IntegerField(
2160 verbose_name='Priority',
2161 help_text='Priority for this ACL (higher numbers are higher priority)',
2162 default = 32768,
2163 validators=[RangeValidator(0, 65535)])
2164
2165 description = models.CharField(
2166 verbose_name='Description',
2167 help_text="Description of the ACL",
2168 max_length=128,
2169 blank=True,
2170 null=True)
2171
2172 #
2173 # end fields ----------------------------------------
2174
2175 class CassandraSettings:
2176 COMPOUND_KEY_FIELDS = ('vns', 'name')
2177
2178 def __unicode__(self):
2179 return self.id
2180
2181 class Rest:
2182 NAME = 'vns-access-list'
2183 FIELD_INFO = (
2184 {'name': 'name', 'rest_name': 'name'},
2185 {'name': 'priority', 'rest_name': 'priority'},
2186 {'name': 'description', 'rest_name': 'description'},
2187 )
2188
2189#
2190# ------------------------------------------------------------
2191
2192class VNSAclEntry(models.Model):
2193 #
2194 # fields ----------------------------------------
2195
2196 rule = models.CharField(
2197 help_text='Rule ID',
2198 validators=[VnsRuleNameValidator()],
2199 max_length=15)
2200
2201 vns_acl = models.ForeignKey(
2202 VNSAcl,
2203 verbose_name='VNS Acl name')
2204
2205 action = models.CharField(
2206 verbose_name='permit or deny',
2207 help_text="'permit' or 'deny'",
2208 max_length=16,
2209 validators=[ VnsAclEntryActionValidator() ])
2210
2211 type = models.CharField(
2212 verbose_name='mac/ip/<0-255>/udp/tcp/icmp',
2213 help_text="ACLtype either mac or ip or udp or tcp or icmp or ip-protocol-type",
2214 max_length=16)
2215
2216 src_ip = models.CharField(
2217 verbose_name='Source IP',
2218 help_text='Source IP Address to match',
2219 validators=[ IpValidator() ],
2220 max_length=15,
2221 blank=True,
2222 null=True)
2223
2224 src_ip_mask = models.CharField(
2225 verbose_name='Source IP Mask',
2226 help_text='Mask to match source IP',
2227 validators=[ IpValidator() ],
2228 max_length=15,
2229 blank=True,
2230 null=True)
2231
2232 src_tp_port_op = models.CharField(
2233 verbose_name='Source Port comparison op',
2234 help_text='Compare with tcp/udp port eq/neq/any',
2235 max_length=5,
2236 blank=True,
2237 null=True)
2238
2239 src_tp_port = models.IntegerField(
2240 verbose_name='Source UDP/TCP Port',
2241 help_text='Source port value to compare',
2242 validators=[RangeValidator(0, 65535)],
2243 blank=True,
2244 null=True)
2245
2246 dst_ip = models.CharField(
2247 verbose_name='Destination IP',
2248 help_text='Destination IP Address to match',
2249 validators=[ IpValidator() ],
2250 max_length=15,
2251 blank=True,
2252 null=True)
2253
2254 dst_ip_mask = models.CharField(
2255 verbose_name='Destination IP Mask',
2256 help_text='Mask to match destination IP',
2257 validators=[ IpValidator() ],
2258 max_length=15,
2259 blank=True,
2260 null=True)
2261
2262 dst_tp_port_op = models.CharField(
2263 verbose_name='Destination Port comparison op',
2264 help_text='Compare with tcp/udp port eq/neq/any',
2265 max_length=3,
2266 blank=True,
2267 null=True)
2268
2269 dst_tp_port = models.IntegerField(
2270 verbose_name='Destination UDP/TCP Port',
2271 help_text='Destination port value to compare',
2272 validators=[RangeValidator(0, 65535)],
2273 blank=True,
2274 null=True)
2275
2276 icmp_type = models.IntegerField(
2277 verbose_name='ICMP Type',
2278 help_text='Matching ICMP type icmp (blank matches all)',
2279 validators=[RangeValidator(0, 255)],
2280 blank=True,
2281 null=True)
2282
2283 src_mac = models.CharField(
2284 verbose_name="Source MAC Address",
2285 help_text="Colon separated hex string (blank matches all)",
2286 max_length=17,
2287 validators = [validate_mac_address],
2288 blank=True,
2289 null=True)
2290
2291 dst_mac = models.CharField(
2292 verbose_name="Destination MAC Address",
2293 help_text="Colon separated hex string (blank matches all)",
2294 max_length=17,
2295 validators = [validate_mac_address],
2296 blank=True,
2297 null=True)
2298
2299 ether_type = models.IntegerField(
2300 verbose_name='Ethernet Packet Type',
2301 help_text='Standard ether type (blank matches all)',
2302 validators=[RangeValidator(1536, 65535)],
2303 blank=True,
2304 null=True)
2305
2306 vlan = models.IntegerField(
2307 verbose_name="VLAN ID",
2308 help_text='Standard ether type (blank matches all)',
2309 blank=True,
2310 null=True,
2311 validators = [ RangeValidator(0, 4095) ])
2312
2313 #
2314 # end fields ----------------------------------------
2315
2316 def __unicode__(self):
2317 return self.id
2318
2319 class CassandraSettings:
2320 COMPOUND_KEY_FIELDS = ('vns_acl', 'rule')
2321
2322 def validate_unique(self, exclude = None):
2323 #
2324 # there are three types of entries:
2325 # - mac based rules
2326 # - ip based rules
2327 # - tcp/udp based rules
2328 #
2329 # verify that for each rules, unexpected fields are not
2330 # populated
2331
2332 if self.type == 'mac':
2333 if self.src_ip or self.src_ip_mask:
2334 raise ValidationError("vns-access-list-entry mac rule:"
2335 " src-ip/src-ip-mask specified"
2336 "(ought to be null)")
2337 if self.dst_ip or self.dst_ip_mask:
2338 raise ValidationError("vns-access-list-entry mac rule:"
2339 " dst-ip/dst-ip-mask specified "
2340 "(ought to be null)")
2341 if self.src_tp_port_op or self.src_tp_port:
2342 raise ValidationError("vns-access-list-entry mac rule:"
2343 " src-tp-port-op/src-to-port specified "
2344 "(ought to be null)")
2345 if self.dst_tp_port_op or self.dst_tp_port:
2346 raise ValidationError("vns-access-list-entry mac rule:"
2347 " dst-tp-port-op/dst-to-port specified "
2348 "(ought to be null)")
2349 if self.icmp_type:
2350 raise ValidationError("vns-access-list-entry mac rule:"
2351 " icmp_type specified "
2352 "(ought to be null)")
2353 elif self.type == 'ip' or re.match('[\d]+', self.type) or \
2354 self.type == 'icmp':
2355 if (self.src_tp_port_op != None or self.src_tp_port != None) and \
2356 ((self.src_tp_port_op == None) or (self.src_tp_port == None)):
2357 raise ValidationError("vns-access-list-entry ip rule:"
2358 " src-tp-port-op/src-to-port specified "
2359 "(both or neither)")
2360 if (self.dst_tp_port_op != None or self.dst_tp_port != None) and \
2361 ((self.dst_tp_port_op == None) or (self.dst_tp_port == None)):
2362 raise ValidationError("vns-access-list-entry ip rule:"
2363 " dst-tp-port-op/dst-to-port specified "
2364 "(both or neither)")
2365 if self.src_mac or self.dst_mac:
2366 raise ValidationError("vns-access-list-entry ip rule:"
2367 " src_mac/dst_mac specified "
2368 "(ought to be null)")
2369 if self.ether_type or self.vlan:
2370 raise ValidationError("vns-access-list-entry ip rule:"
2371 " ether-type/vlan specified "
2372 "(ought to be null)")
2373
2374 elif self.type == 'tcp' or self.type == 'udp':
2375 if self.src_mac or self.dst_mac:
2376 raise ValidationError("vns-access-list-entry ip rule:"
2377 " src_mac/dst_mac specified "
2378 "(ought to be null)")
2379 if self.ether_type or self.vlan:
2380 raise ValidationError("vns-access-list-entry ip rule:"
2381 " ether-type/vlan specified "
2382 "(ought to be null)")
2383
2384
2385 class Rest:
2386 NAME = 'vns-access-list-entry'
2387 FIELD_INFO = (
2388 {'name': 'vns_acl', 'rest_name': 'vns-access-list'},
2389 {'name': 'src_ip', 'rest_name': 'src-ip'},
2390 {'name': 'src_ip_mask', 'rest_name': 'src-ip-mask'},
2391 {'name': 'dst_ip', 'rest_name': 'dst-ip'},
2392 {'name': 'dst_ip_mask', 'rest_name': 'dst-ip-mask'},
2393 {'name': 'src_tp_port_op', 'rest_name': 'src-tp-port-op'},
2394 {'name': 'src_tp_port', 'rest_name': 'src-tp-port'},
2395 {'name': 'dst_tp_port_op', 'rest_name': 'dst-tp-port-op'},
2396 {'name': 'dst_tp_port', 'rest_name': 'dst-tp-port'},
2397 {'name': 'icmp_type', 'rest_name': 'icmp-type'},
2398 {'name': 'src_mac', 'rest_name': 'src-mac'},
2399 {'name': 'dst_mac', 'rest_name': 'dst-mac'},
2400 {'name': 'ether_type', 'rest_name': 'ether-type'},
2401 )
2402
2403#
2404# ------------------------------------------------------------
2405
2406class VNSInterfaceAcl(models.Model):
2407 in_out_length = 4
2408
2409 #
2410 # fields ----------------------------------------
2411
2412 vns_acl = models.ForeignKey(
2413 VNSAcl,
2414 verbose_name='VNS Acl name')
2415
2416 vns_interface = models.ForeignKey(
2417 VNSInterfaceConfig,
2418 verbose_name='VNS Interface ID',
2419 help_text='[vns id]|[interface long name]')
2420
2421 in_out = models.CharField(
2422 verbose_name='in/out',
2423 help_text='Match on packet input or output',
2424 validators=[VnsInterfaceAclInOutValidator()],
2425 max_length=in_out_length,
2426 )
2427
2428 #
2429 # end fields ----------------------------------------
2430
2431 def __unicode__(self):
2432 return self.id
2433
2434 class CassandraSettings:
2435 COMPOUND_KEY_FIELDS = ('vns_interface', 'vns_acl', 'in_out')
2436
2437 def validate_unique(self, exclude = None):
2438 acl_parts = str(self.vns_acl).split('|')
2439 intf_parts = str(self.vns_interface).split('|')
2440 # validate two vns parts
2441 if acl_parts[0] != intf_parts[0]:
2442 raise ValidationError("acl's vns %s doen't match interface vns %s" %
2443 (acl_parts[0], intf_parts[0]))
2444 error = False
2445 try:
2446 exists = VNSInterfaceAcl.objects.get(vns_interface=self.vns_interface, in_out=self.in_out)
2447 if exists:
2448 if exists.vns_acl != self.vns_acl:
2449 error = True
2450 except:
2451 pass
2452 if error:
2453 raise ValidationError("Interface %s already has an ACL in the %s direction, only one ACL per direction allowed" % (self.vns_interface, self.in_out))
2454
2455 class Rest:
2456 NAME = 'vns-interface-access-list'
2457 FIELD_INFO = (
2458 {'name': 'vns_acl', 'rest_name': 'vns-access-list'},
2459 {'name': 'vns_interface', 'rest_name': 'vns-interface'},
2460 {'name': 'in_out', 'rest_name': 'in-out'},
2461 )
2462
2463#
2464# ------------------------------------------------------------
2465# A virtual router interface separation
2466
2467class VirtualRouterInterface (models.Model):
2468
2469 id_max_length = 64
2470 #
2471 # fields ----------------------------------------
2472 virtual_router = models.ForeignKey(
2473 VirtualRouter,
2474 verbose_name='Virtual Router ID')
2475 #
2476 # Unique name of the interface
2477 #
2478 vriname = models.CharField(
2479 verbose_name = 'Interface Name',
2480 help_text = 'A unique name for a virtual router interface',
2481 validators = [ GeneralNameValidator() ],
2482 max_length = id_max_length)
2483 #
2484 # Origin of this configured item
2485 #
2486 origin = models.CharField(
2487 verbose_name = "Origin",
2488 help_text = "Values: cli, rest, other packages",
2489 max_length = 64, # in future we might use SW GUIDs for this field
2490 blank = True,
2491 null = True)
2492 #
2493 # Whether the configuration is active ? By default, it is active
2494 # Used to disable the configuration without having to delete the entire
2495 # interface configuration construct.
2496 #
2497 active = models.BooleanField(
2498 verbose_name = 'Active',
2499 help_text = 'Is this interface active (default is True)',
2500 default = True)
2501 vns_connected = models.ForeignKey(
2502 VNS,
2503 verbose_name='VNS connected to',
2504 blank =True,
2505 null =True)
2506 router_connected = models.ForeignKey(
2507 VirtualRouter,
2508 related_name='router_connected',
2509 verbose_name='Virtual Router connected to',
2510 blank =True,
2511 null =True)
2512
2513 #
2514 # end fields ----------------------------------------
2515
2516 def __unicode__ (self):
2517 return self.id
2518
2519 def validate_unique(self, exclude = None):
2520 def is_set(value):
2521 if value != None and value != '':
2522 return True
2523
2524 # for vns connection, verify that only the VNSs under the same tenant can be connected
2525 error=False
2526 if not 'vns_connected' in exclude:
2527 if is_set(self.vns_connected):
2528 tenant_vns_parts = str(self.vns_connected).split('|')
2529 tenant_router_parts = str(self.virtual_router).split('|')
2530 if tenant_vns_parts[0] != tenant_router_parts[0]:
2531 raise ValidationError(" VNS %s belongs to tenant %s, doesn't match virtual router tenant %s" %
2532 (tenant_vns_parts[1],tenant_vns_parts[0], tenant_router_parts[0]))
2533 # verify there can only be one connection for one VNS
2534 try:
2535 exists = VirtualRouterInterface.objects.get(virtual_router = self.virtual_router, vns_connected=self.vns_connected)
2536 if exists:
2537 if exists.vriname!=self.vriname:
2538 error=True
2539 except:
2540 pass
2541 if error:
2542 raise ValidationError(" VNS %s has been connected, multiple connections is not allowed" % self.vns_connected)
2543 error = False
2544 # for router connection, verify that the same virtual router as myself can't be connected
2545 if not 'router_connected' in exclude:
2546 if is_set(self.router_connected):
2547 tenant_router_parts = str(self.router_connected).split('|')
2548 tenant_myrouter_parts = str(self.virtual_router).split('|')
2549 if tenant_router_parts[0] == tenant_myrouter_parts[0]:
2550 raise ValidationError(" Local loop conncetion is not allowed.")
2551 # verify there can only be one connection for one virtual router
2552 try:
2553 exists = VirtualRouterInterface.objects.get(virtual_router = self.virtual_router,router_connected=self.router_connected)
2554 if exists:
2555 if exists.vriname!=self.vriname:
2556 error=True
2557 except:
2558 pass
2559 if error:
2560 raise ValidationError(" Virtual Router %s has been connected, multiple connections is not allowed" % self.router_connected)
2561
2562 class CassandraSettings:
2563 COMPOUND_KEY_FIELDS = ('virtual_router', 'vriname')
2564
2565 class Rest:
2566 NAME = 'virtualrouter-interface'
2567 FIELD_INFO = (
2568 {'name': 'vns_connected', 'rest_name': 'vns-connected'},
2569 {'name': 'router_connected', 'rest_name': 'router-connected'},
2570 {'name': 'virtual_router', 'rest_name': 'virtual-router'},
2571
2572 )
2573
2574#
2575# ------------------------------------------------------------
2576# A virtual router interface address pool separation
2577
2578class VRInterfaceIpAddressPool (models.Model):
2579
2580 id_max_length = 64
2581 #
2582 # fields ----------------------------------------
2583 virtual_router_interface = models.ForeignKey(
2584 VirtualRouterInterface,
2585 verbose_name='Virtual Router Interface ID')
2586 #
2587 # Origin of this configured item
2588 #
2589 origin = models.CharField(
2590 verbose_name = "Origin",
2591 help_text = "Values: cli, rest, other packages",
2592 max_length = 64,
2593 blank = True,
2594 null = True)
2595 ip_address = models.CharField(
2596 verbose_name='Source IP',
2597 help_text='Interface IP Address',
2598 validators=[ IpValidator() ],
2599 max_length=15,
2600 blank=True,
2601 null=True)
2602 subnet_mask = models.CharField(
2603 verbose_name='Subnet IP Mask',
2604 validators=[ IpMaskValidator() ],
2605 max_length=15,
2606 blank=True,
2607 null=True)
2608
2609 #
2610 # end fields ----------------------------------------
2611
2612 def __unicode__ (self):
2613 return self.id
2614
2615 class CassandraSettings:
2616 COMPOUND_KEY_FIELDS = ('virtual_router_interface', 'ip_address')
2617
2618 class Rest:
2619 NAME = 'interface-address-pool'
2620 FIELD_INFO = (
2621 {'name': 'virtual_router_interface', 'rest_name': 'virtual-router-interface'},
2622 {'name': 'ip_address', 'rest_name': 'ip-address'},
2623 {'name': 'subnet_mask', 'rest_name': 'subnet-mask'},
2624 )
2625
2626
2627#
2628# ------------------------------------------------------------
2629
2630class VirtualRouterGWPool (models.Model):
2631
2632 id_max_length = 64
2633 #
2634 # fields ----------------------------------------
2635 virtual_router = models.ForeignKey(
2636 VirtualRouter,
2637 verbose_name='Virtual Router ID')
2638 #
2639 # Unique name of the gateway pool
2640 #
2641 vrgwname = models.CharField(
2642 verbose_name = 'Gateway Pool Name',
2643 help_text = 'A unique name for a virtual router gateway pool',
2644 validators = [ GeneralNameValidator() ],
2645 max_length = id_max_length)
2646
2647 #
2648 # end fields ----------------------------------------
2649
2650 def __unicode__ (self):
2651 return self.id
2652
2653 def validate_unique(self, exclude = None):
2654 def is_set(value):
2655 if value != None and value != '':
2656 return True
2657
2658 class CassandraSettings:
2659 COMPOUND_KEY_FIELDS = ('virtual_router', 'vrgwname')
2660
2661 class Rest:
2662 NAME = 'virtualrouter-gwpool'
2663 FIELD_INFO = (
2664 {'name': 'virtual_router', 'rest_name': 'virtual-router'},
2665 )
2666
2667#
2668# ------------------------------------------------------------
2669# A virtual router gateway address pool separation
2670
2671class VRGatewayIpAddressPool (models.Model):
2672
2673 id_max_length = 64
2674 #
2675 # fields ----------------------------------------
2676 virtual_router_gwpool = models.ForeignKey(
2677 VirtualRouterGWPool,
2678 verbose_name='Virtual Router Gateway Pool ID')
2679 ip_address = models.CharField(
2680 verbose_name='Gateway IP',
2681 help_text='Gateway IP Address',
2682 validators=[ IpValidator() ],
2683 max_length=15,
2684 blank=True,
2685 null=True)
2686
2687 #
2688 # end fields ----------------------------------------
2689
2690 def __unicode__ (self):
2691 return self.id
2692
2693 class CassandraSettings:
2694 COMPOUND_KEY_FIELDS = ('virtual_router_gwpool', 'ip_address')
2695
2696 class Rest:
2697 NAME = 'gateway-address-pool'
2698 FIELD_INFO = (
2699 {'name': 'virtual_router_gwpool', 'rest_name': 'virtual-router-gwpool'},
2700 {'name': 'ip_address', 'rest_name': 'ip-address'},
2701 )
2702
2703class VirtualRoutingRule (models.Model):
2704
2705 id_max_length = 64
2706 #
2707 # fields ----------------------------------------
2708 virtual_router = models.ForeignKey(
2709 VirtualRouter,
2710 verbose_name='Virtual Router ID')
2711 #
2712 # Origin of this configured item
2713 #
2714 origin = models.CharField(
2715 verbose_name = "Origin",
2716 help_text = "Values: cli, rest, other packages",
2717 max_length = 64,
2718 blank = True,
2719 null = True)
2720 src_host = models.ForeignKey(
2721 HostConfig,
2722 verbose_name='source Host ID',
2723 help_text='Source Host ID to match',
2724 blank =True,
2725 null =True)
2726 src_tenant = models.ForeignKey(
2727 Tenant,
2728 verbose_name='source tenant ID',
2729 help_text='Source tenant ID to match',
2730 blank =True,
2731 null =True)
2732 src_vns = models.ForeignKey(
2733 VNS,
2734 verbose_name='source VNS ID',
2735 help_text='Source VNS ID to match',
2736 blank =True,
2737 null =True)
2738 src_ip = models.CharField(
2739 verbose_name='Source IP',
2740 help_text='Source IP Address to match',
2741 validators=[ IpValidator() ],
2742 max_length=15,
2743 blank=True,
2744 null=True)
2745 src_ip_mask = models.CharField(
2746 verbose_name='Source IP Mask',
2747 help_text='Mask to match source IP',
2748 validators=[ IpMaskValidator() ],
2749 max_length=15,
2750 blank=True,
2751 null=True)
2752 dst_host = models.ForeignKey(
2753 HostConfig,
2754 verbose_name='Destination Host ID',
2755 help_text='Destination Host ID to match',
2756 related_name='dest_host',
2757 blank =True,
2758 null =True)
2759 dst_tenant = models.ForeignKey(
2760 Tenant,
2761 verbose_name='Destination tenant ID',
2762 related_name='dest_tenant',
2763 blank =True,
2764 null =True)
2765 dst_vns = models.ForeignKey(
2766 VNS,
2767 verbose_name='Destination VNS ID',
2768 related_name='dest_vns',
2769 blank =True,
2770 null =True)
2771 dst_ip = models.CharField(
2772 verbose_name='Destination IP',
2773 help_text='Destination IP Address to match',
2774 validators=[ IpValidator() ],
2775 max_length=15,
2776 blank=True,
2777 null=True)
2778 dst_ip_mask = models.CharField(
2779 verbose_name='Destination IP Mask',
2780 help_text='Mask to match destination IP',
2781 validators=[ IpMaskValidator() ],
2782 max_length=15,
2783 blank=True,
2784 null=True)
2785 outgoing_intf = models.ForeignKey(
2786 VirtualRouterInterface,
2787 verbose_name='Outgoing Interface',
2788 blank =True,
2789 null =True)
2790 gateway_pool = models.ForeignKey(
2791 VirtualRouterGWPool,
2792 verbose_name='Gateway pool',
2793 blank =True,
2794 null =True)
2795 nh_ip = models.CharField(
2796 verbose_name='Next Hop IP',
2797 help_text='Next Hop IP Address',
2798 validators=[ IpValidator() ],
2799 max_length=15,
2800 blank=True,
2801 null=True)
2802 action = models.CharField(
2803 verbose_name='permit or deny',
2804 help_text="'permit' or 'deny'",
2805 default='permit',
2806 max_length=16,
2807 validators=[ VnsAclEntryActionValidator() ])
2808 #
2809 # end fields ----------------------------------------
2810
2811 def __unicode__ (self):
2812 return self.id
2813
2814 def validate_unique(self, exclude = None):
2815 def is_set(value):
2816 if value != None and value != '':
2817 return True
2818 #verify the outgoing interface can only be on the local virtual router interface
2819 if not 'outgoing_intf' in exclude:
2820 if is_set(self.outgoing_intf):
2821 router_parts = str(self.outgoing_intf).split('|')
2822 myrouter_parts = str(self.virtual_router).split('|')
2823 if (router_parts[0] != myrouter_parts[0]) or (router_parts[1] != myrouter_parts[1]):
2824 raise ValidationError(" outgoing interface has to be local to virtual router: %s|%s" %
2825 (myrouter_parts[0],myrouter_parts[1]))
2826 #verify the gateway pool belongs to the local virtual router
2827 if not 'gateway_pool' in exclude:
2828 if is_set(self.gateway_pool):
2829 router_parts = str(self.gateway_pool).split('|')
2830 myrouter_parts = str(self.virtual_router).split('|')
2831 if (router_parts[0] != myrouter_parts[0]) or (router_parts[1] != myrouter_parts[1]):
2832 raise ValidationError(" gateway pool has to be local to virtual router: %s|%s" %
2833 (myrouter_parts[0],myrouter_parts[1]))
2834
2835 class CassandraSettings:
2836 COMPOUND_KEY_FIELDS = ('virtual_router', 'src_host', 'src_tenant','src_vns','src_ip','src_ip_mask', 'dst_host', 'dst_tenant','dst_vns','dst_ip','dst_ip_mask')
2837
2838 class Rest:
2839 NAME = 'virtualrouter-routingrule'
2840 FIELD_INFO = (
2841 {'name': 'virtual_router', 'rest_name': 'virtual-router'},
2842 {'name': 'src_tenant', 'rest_name': 'src-tenant'},
2843 {'name': 'dst_tenant', 'rest_name': 'dst-tenant'},
2844 {'name': 'src_vns', 'rest_name': 'src-vns'},
2845 {'name': 'src_ip', 'rest_name': 'src-ip'},
2846 {'name': 'src_ip_mask', 'rest_name': 'src-ip-mask'},
2847 {'name': 'dst_ip', 'rest_name': 'dst-ip'},
2848 {'name': 'dst_ip_mask', 'rest_name': 'dst-ip-mask'},
2849 {'name': 'nh_ip', 'rest_name': 'nh-ip'},
2850 {'name': 'outgoing_intf', 'rest_name': 'outgoing-intf'},
2851 {'name': 'dst_host', 'rest_name': 'dst-host'},
2852 {'name': 'src_host', 'rest_name': 'src-host'},
2853 {'name': 'dst_vns', 'rest_name': 'dst-vns'},
2854 {'name': 'gateway_pool', 'rest_name': 'gateway-pool'},
2855 )
srikanthf2c888b2014-08-20 10:46:55 -07002856"""
srikanth116e6e82014-08-19 07:22:37 -07002857#
2858# ------------------------------------------------------------
2859
2860class Tag(models.Model):
2861 namespace_length = 64
2862 name_length = 64
2863 value_length = 64
2864
2865 #
2866 # fields ----------------------------------------
2867
2868 namespace = models.CharField(
2869 verbose_name='Tag Namespace',
2870 help_text="Namespace of the tag",
2871 max_length=namespace_length)
2872
2873 name = models.CharField(
2874 verbose_name='Tag Name',
2875 help_text="Name of the tag",
2876 max_length=name_length)
2877
2878 value = models.CharField(
2879 verbose_name='Tag Value',
2880 help_text="Value of the tag",
2881 max_length=value_length)
2882
2883 persist = models.BooleanField(
2884 verbose_name='persist',
2885 help_text='For any cli configured tag, include in running-config',
2886 default=True)
2887
2888 #
2889 # end fields ----------------------------------------
2890
2891 def __unicode__(self):
2892 return self.id
2893
2894 class CassandraSettings:
2895 COMPOUND_KEY_FIELDS = ('namespace', 'name', 'value')
2896
2897 class Rest:
2898 NAME = 'tag'
2899
2900#
2901# ------------------------------------------------------------
2902
2903class TagMapping(models.Model):
2904 host_id_length = 17
2905 switch_id_length = 23
2906 if_name_len = 32
2907 vlan_str_len = 4
2908 #
2909 # fields ----------------------------------------
2910
2911 tag = models.ForeignKey(
2912 Tag)
2913
2914 mac = models.CharField(
2915 verbose_name="MAC Address",
2916 max_length=host_id_length,
2917 validators = [validate_mac_address],
2918 default="",
2919 blank=True)
2920
2921 vlan = models.CharField(
2922 verbose_name='VLAN',
2923 max_length=vlan_str_len,
2924 help_text='VLAN Number, in the range of 1-4095. 4095 means untagged',
2925 validators=[VlanStringValidator()],
2926 default="",
2927 blank=True)
2928
2929 dpid = models.CharField(
2930 verbose_name='Switch DPID',
2931 help_text='Switch DPID - 64-bit hex separated by :',
2932 max_length=switch_id_length,
2933 validators=[ validate_dpid ],
2934 default="",
2935 blank=True)
2936
2937 ifname = models.CharField(
2938 verbose_name='If Name regular expression',
2939 max_length=if_name_len,
2940 default="",
2941 validators=[ SafeForPrimaryKeyValidator() ],
2942 blank=True)
2943
2944 #
2945 # end fields ----------------------------------------
2946
2947 def __unicode__(self):
2948 return self.id
2949
2950 class CassandraSettings:
2951 COMPOUND_KEY_FIELDS = ('tag', 'mac', 'vlan', 'dpid', 'ifname')
2952
2953 def validate_unique(self, exclude = None):
2954 if self.mac != '':
2955 self.mac = self.mac.lower()
2956
2957 if self.dpid != '':
2958 self.dpid = self.dpid.lower()
2959
2960 # don't allow all default values for the association
2961 if self.mac == '' and self.vlan == '' and \
2962 self.dpid == '' and self.ifname == '':
2963 raise ValidationError("Match without any matching fields")
2964
2965 class Rest:
2966 NAME = 'tag-mapping'
2967
2968#
2969# ------------------------------------------------------------
srikanthf2c888b2014-08-20 10:46:55 -07002970"""
srikanth116e6e82014-08-19 07:22:37 -07002971class TechSupportConf(models.Model):
2972
2973 #
2974 # fields ----------------------------------------
2975
2976 cmd_type = models.CharField(
2977 verbose_name='Type of command',
2978 help_text='Enter cli or shell',
2979 max_length=32)
2980
2981 cmd = models.CharField(
2982 max_length=256,
2983 verbose_name='Command name',
2984 help_text = 'Command excuted by show tech-support')
2985
2986
2987 #
2988 # end fields ----------------------------------------
2989
2990 def __unicode__(self):
2991 return self.id
2992
2993 class CassandraSettings:
2994 COMPOUND_KEY_FIELDS = ('cmd_type', 'cmd')
2995
2996 class Rest:
2997 NAME = 'tech-support-config'
2998 FIELD_INFO = (
2999 {'name': 'cmd_type', 'rest_name': 'cmd-type'},
3000 )
3001
3002#
3003# ------------------------------------------------------------
3004
3005class TacacsPlusConfig(models.Model):
3006 #
3007 # fields ----------------------------------------
3008
3009 id = models.CharField(
3010 primary_key=True,
3011 verbose_name='tacacs singleton',
3012 default='tacacs',
3013 max_length=16)
3014
3015 tacacs_plus_authn = models.BooleanField(
3016 verbose_name='TACACS+ Authentication Enabled',
3017 help_text='Enable TACACS+ authentication by setting to true',
3018 default=False
3019 )
3020
3021 tacacs_plus_authz = models.BooleanField(
3022 verbose_name='TACACS+ Authorization Enabled',
3023 help_text='Enable TACACS+ authorization by setting to true',
3024 default=False
3025 )
3026
3027 tacacs_plus_acct = models.BooleanField(
3028 verbose_name='TACACS+ Accounting Enabled',
3029 help_text='Enable TACACS+ accounting by setting to true',
3030 default=False
3031 )
3032
3033 local_authn = models.BooleanField(
3034 verbose_name='Local Authentication Enabled',
3035 help_text='Enable local authentication by setting to true',
3036 default=True
3037 )
3038
3039 local_authz = models.BooleanField(
3040 verbose_name='Local Authorization Enabled',
3041 help_text='Enable local authorization by setting to true',
3042 default=True
3043 )
3044
3045 timeout = models.IntegerField(
3046 verbose_name="TACACS+ Server Timeout",
3047 help_text='Set TACACS+ server timeout in seconds',
3048 default=0,
3049 validators=[ RangeValidator(0, 2**16-1) ])
3050
3051 key = models.CharField(
3052 verbose_name='TACACS+ Pre-shared Key',
3053 help_text='pre-shared key to connect to TACACS+ server(s)',
3054 max_length=256,
3055 blank=True,
3056 default="")
3057
3058 #
3059 # end fields ----------------------------------------
3060
3061 class Rest:
3062 NAME = 'tacacs-plus-config'
3063 FIELD_INFO = (
3064 {'name': 'tacacs_plus_authn', 'rest_name': 'tacacs-plus-authn'},
3065 {'name': 'tacacs_plus_authz', 'rest_name': 'tacacs-plus-authz'},
3066 {'name': 'tacacs_plus_acct', 'rest_name': 'tacacs-plus-acct'},
3067 {'name': 'local_authn', 'rest_name': 'local-authn'},
3068 {'name': 'local_authz', 'rest_name': 'local-authz'},
3069 )
3070
3071#
3072# ------------------------------------------------------------
3073
3074class TacacsPlusHost(models.Model):
3075 #
3076 # fields ----------------------------------------
3077
3078 ip = models.CharField(
3079 primary_key=True,
3080 verbose_name='IP Address',
3081 help_text='IP Address for TACACS+ server',
3082 validators=[ IpValidator() ],
3083 max_length=15)
3084
3085 timestamp = models.PositiveIntegerField(
3086 verbose_name='timestamp',
3087 help_text='Timestamp to order the tacacs servers',
3088 default = get_timestamp,
3089 )
3090
3091 key = models.CharField(
3092 verbose_name='TACACS+ Per-host Pre-shared Key',
3093 help_text='pre-shared key to connect to this TACACS+ server',
3094 max_length=256,
3095 blank=True,
3096 default="")
3097
3098 #
3099 # end fields ----------------------------------------
3100
3101 def __unicode__(self):
3102 return "%s" % self.ip
3103
3104 def validate_unique(self, exclude = None):
3105 try:
3106 exists = TacacsPlusHost.objects.get(ip = self.ip)
3107
3108 if exists.timestamp != self.timestamp:
3109 self.timestamp = exists.timestamp
3110 except:
3111 pass
3112
3113 class Rest:
3114 NAME = 'tacacs-plus-host'
3115 FIELD_INFO = (
3116 )
3117
3118#
3119#---------------------------------------------------------
3120
3121class SnmpServerConfig(models.Model):
3122 #
3123 # fields ----------------------------------------
3124
3125 # we just have one row entry in the table to update, so static primary key
3126 id = models.CharField(
3127 primary_key=True,
3128 verbose_name='snmp',
3129 # default='snmp',
3130 max_length=16)
3131
3132 #
3133 # Enable state of the SNMP server/agent on the controller
3134 #
3135 server_enable = models.BooleanField(
3136 verbose_name='SNMP Server enabled',
3137 help_text='Enable SNMP server by setting to true',
3138 default=False
3139 )
3140 #
3141 # Community string for accessing the SNMP server on the controller
3142 #
3143 community = models.CharField(
3144 verbose_name = 'Community String',
3145 help_text = "Community String to access SNMP data",
3146 max_length = 128,
3147 null = True,
3148 blank = True,
3149 )
3150 #
3151 # Location string of the SNMP server on the controller
3152 #
3153 location = models.CharField(
3154 verbose_name = 'System Location',
3155 help_text = "Location information for the controller appliance",
3156 max_length = 128,
3157 null = True,
3158 blank = True
3159 )
3160 #
3161 # Contact string of the SNMP server on the controller
3162 #
3163 contact = models.CharField(
3164 verbose_name = 'System Contact',
3165 help_text = "Contact information for the controller appliance",
3166 max_length = 128,
3167 null = True,
3168 blank = True,
3169 )
3170 #
3171 # end fields ----------------------------------------
3172
3173 def __unicode__(self):
3174 return self.id
3175
3176 def validate_unique(self, exclude = None):
3177 if self.id != 'snmp':
3178 raise ValidationError("Only single snmp record exists")
3179
3180 class Rest:
3181 NAME = 'snmp-server-config'
3182 FIELD_INFO = (
3183 {'name': 'server_enable', 'rest_name': 'server-enable'},
3184 )
3185
3186#
3187# ------------------------------------------------------------
3188
3189class ImageDropUser(models.Model):
3190 #
3191 # fields ----------------------------------------
3192
3193 # we just have one row entry in the table to update, so static primary key
3194 id = models.CharField(
3195 primary_key=True,
3196 verbose_name='imagedropuser',
3197 default='imagedropuser',
3198 max_length=16)
3199
3200 images_user_ssh_key = models.CharField(
3201 verbose_name='Image drop user SSH public key',
3202 help_text='The SSH public RSA key for the images user',
3203 default='',
3204 max_length=600
3205 )
3206 #
3207 # end fields ----------------------------------------
3208
3209 def __unicode__(self):
3210 return self.id
3211
3212 def validate_unique(self, exclude = None):
3213 if self.id != 'imagedropuser':
3214 raise ValidationError("Only single ImageDropUser record exists")
3215
3216 class Rest:
3217 NAME = 'image-drop-user'
3218 FIELD_INFO = (
3219 {'name': 'images_user_ssh_key', 'rest_name': 'images-user-ssh-key'},
3220 )
3221
3222# robv: Commenting out for now. Doesn't work with Cassandra backend
3223#class ConsoleUser(User):
3224#
3225# class Meta:
3226# proxy = True
3227#
3228# class Rest:
3229# NAME = 'user'
srikanthf2c888b2014-08-20 10:46:55 -07003230"""