Plugins for configuration manager
[ta/cm-plugins.git] / validators / src / TimeValidation.py
1 #!/usr/bin/python
2 # Copyright 2019 Nokia
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #    http://www.apache.org/licenses/LICENSE-2.0
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 implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 # pylint: disable=line-too-long
17
18 import logging
19 import json
20 import pytz
21 import yaml
22 import requests
23 from django.core.validators import URLValidator
24 from django.core.exceptions import ValidationError
25
26 from cmframework.apis import cmvalidator
27 from cmdatahandlers.api import validation
28
29
30 class TimeValidation(cmvalidator.CMValidator):
31     domain = 'cloud.time'
32     supported_authentication_types = ['none', 'crypto', 'symmetric']
33
34     def get_subscription_info(self):
35         logging.debug('get_subscription info called')
36         return r'^cloud\.time$'
37
38     def validate_set(self, dict_key_value):
39         ntp_attr = 'ntp_servers'
40         logging.debug('validate_set called with %s' % str(dict_key_value))
41
42         for key, value in dict_key_value.iteritems():
43             value_dict = json.loads(value)
44             if not value_dict:
45                 raise validation.ValidationError('No value for %s' % key)
46             if not isinstance(value_dict, dict):
47                 raise validation.ValidationError('%s value is not a dict' % self.domain)
48
49             if key == self.domain:
50                 ntp_list = value_dict.get(ntp_attr)
51
52                 self.validate_ntp(ntp_list)
53
54                 attr = 'zone'
55                 zone = value_dict.get(attr)
56                 if zone:
57                     self.validate_timezone(zone)
58                 else:
59                     raise validation.ValidationError('Missing timezone %s' % attr)
60
61                 auth_type = value_dict.get('auth_type')
62                 if auth_type:
63                     self.validate_authtype(auth_type)
64                 else:
65                     raise validation.ValidationError('Missing authentication type for NTP')
66
67                 filepath = value_dict.get('serverkeys_path')
68                 if auth_type != 'none' and filepath == '':
69                     raise validation.ValidationError('The serverkeys_path is missing')
70                 elif auth_type == 'none':
71                     pass
72                 else:
73                     self.validate_filepath(filepath)
74                     self.validate_yaml_format(filepath, auth_type)
75             else:
76                 raise validation.ValidationError('Unexpected configuration %s' % key)
77
78     def validate_delete(self, dict_key_value):
79         logging.debug('validate_delete called with %s' % str(dict_key_value))
80         raise validation.ValidationError('%s cannot be deleted' % self.domain)
81
82     def validate_ntp(self, ntp_list):
83         if not ntp_list:
84             raise validation.ValidationError('Missing NTP configuration')
85
86         if not isinstance(ntp_list, list):
87             raise validation.ValidationError('NTP servers value must be a list')
88         utils = validation.ValidationUtils()
89         for ntp in ntp_list:
90             utils.validate_ip_address(ntp)
91
92     def validate_timezone(self, value):
93         try:
94             pytz.timezone(value)
95         except pytz.UnknownTimeZoneError as exc:
96             raise validation.ValidationError("Invalid time zone: {0}".format(exc))
97
98     def validate_authtype(self, auth_type):
99         if auth_type not in TimeValidation.supported_authentication_types:
100             raise validation.ValidationError(
101                 'The provided authentication method for NTP is not supported')
102
103     def validate_filepath(self, filepath):
104         try:
105             val = URLValidator()
106             val(filepath)
107         except ValidationError:
108             raise validation.ValidationError('The url: "%s" is not a valid url!' % filepath)
109
110     def validate_yaml_format(self, url, auth_type):
111         if url.startswith("file://"):
112             path = url.lstrip("file://")
113             try:
114                 with open(path) as f:
115                     f_content = f.read()
116             except IOError:
117                 raise validation.ValidationError('The file: "%s" is not present on the system!'
118                                                  % url)
119         else:
120             try:
121                 r = requests.get(url)
122                 if r['status_code'] != 200:
123                     raise requests.exceptions.ConnectionError()
124                 f_content = r['content']
125             except requests.exceptions.ConnectionError:
126                 raise validation.ValidationError('The url: "%s" is not reachable!' % url)
127         try:
128             yaml_content = yaml.load(f_content)
129         except yaml.YAMLError:
130             raise validation.ValidationError('The validation of the yamlfile failed!')
131         for item in yaml_content:
132             srv = item.keys()[0]
133             if auth_type == 'symmetric' and not isinstance(item[srv], str):
134                 raise validation.ValidationError('The yamlfile contains invalid data! '
135                                                  '(The authentication method looks like it\'s symmetric.)')
136             elif auth_type == 'crypto' and isinstance(item[srv], dict):
137                 if (item[srv]['type'] != 'iff' or item[srv]['type'] != 'gq' or
138                     item[srv]['type'] != 'mv')\
139                    and (not isinstance(item[srv]['keys'], list)):
140                     raise validation.ValidationError('The yamlfile contains invalid data! '
141                                                      '(The authentication method looks like it\'s crypto.)')
142             else:
143                 raise validation.ValidationError('The yamlfile contains invalid data!')