separate baseoption and option
[tiramisu.git] / tiramisu / option / ipoption.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2017 Team tiramisu (see AUTHORS for all contributors)
3 #
4 # This program is free software: you can redistribute it and/or modify it
5 # under the terms of the GNU Lesser General Public License as published by the
6 # Free Software Foundation, either version 3 of the License, or (at your
7 # option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful, but WITHOUT
10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
12 # details.
13 #
14 # You should have received a copy of the GNU Lesser General Public License
15 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 #
17 # The original `Config` design model is unproudly borrowed from
18 # the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
19 # the whole pypy projet is under MIT licence
20 # ____________________________________________________________
21 from IPy import IP
22
23 from ..error import ConfigError
24 from ..setting import undefined
25 from ..i18n import _
26 from .option import Option
27
28
29 class IPOption(Option):
30     "represents the choice of an ip"
31     __slots__ = tuple()
32     _display_name = _('IP')
33
34     def __init__(self, name, doc, default=None, default_multi=None,
35                  requires=None, multi=False, callback=None,
36                  callback_params=None, validator=None, validator_params=None,
37                  properties=None, private_only=False, allow_reserved=False,
38                  warnings_only=False):
39         extra = {'_private_only': private_only,
40                  '_allow_reserved': allow_reserved}
41         super(IPOption, self).__init__(name, doc, default=default,
42                                        default_multi=default_multi,
43                                        callback=callback,
44                                        callback_params=callback_params,
45                                        requires=requires,
46                                        multi=multi,
47                                        validator=validator,
48                                        validator_params=validator_params,
49                                        properties=properties,
50                                        warnings_only=warnings_only,
51                                        extra=extra)
52
53     def _validate(self, value, context=undefined, current_opt=undefined):
54         # sometimes an ip term starts with a zero
55         # but this does not fit in some case, for example bind does not like it
56         err = self._impl_valid_unicode(value)
57         if err:
58             return err
59         if value.count('.') != 3:
60             return ValueError()
61         for val in value.split('.'):
62             if val.startswith("0") and len(val) > 1:
63                 return ValueError()
64         # 'standard' validation
65         try:
66             IP('{0}/32'.format(value))
67         except ValueError:
68             return ValueError()
69
70     def _second_level_validation(self, value, warnings_only):
71         ip = IP('{0}/32'.format(value))
72         if not self._get_extra('_allow_reserved') and ip.iptype() == 'RESERVED':
73             if warnings_only:
74                 msg = _("shouldn't in reserved class")
75             else:
76                 msg = _("mustn't be in reserved class")
77             return ValueError(msg)
78         if self._get_extra('_private_only') and ip.iptype() != 'PRIVATE':
79             if warnings_only:
80                 msg = _("should be in private class")
81             else:
82                 msg = _("must be in private class")
83             return ValueError(msg)
84
85     def _cons_in_network(self, current_opt, opts, vals, warnings_only):
86         if len(vals) != 3:
87             raise ConfigError(_('invalid len for vals'))
88         if None in vals:
89             return
90         ip, network, netmask = vals
91         if IP(ip) not in IP('{0}/{1}'.format(network, netmask)):
92             msg = _('{4} is not in network {0}/{1} ({2}/{3})')
93             return ValueError(msg.format(network, netmask,
94                                          opts[1].impl_getname(), opts[2].impl_getname(), ip))
95         # test if ip is not network/broadcast IP
96         return opts[2]._cons_ip_netmask(current_opt, (opts[2], opts[0]), (netmask, ip), warnings_only)