Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1#!/usr/bin/env python3 

2# Copyright 2020 Canonical Ltd. 

3# 

4# Licensed under the Apache License, Version 2.0 (the "License"); you may 

5# not use this file except in compliance with the License. You may obtain 

6# 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, WITHOUT 

12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 

13# License for the specific language governing permissions and limitations 

14# under the License. 

15# 

16# For those usages not covered by the Apache License, Version 2.0 please 

17# contact: legal@canonical.com 

18# 

19# To get in touch with the maintainers, please contact: 

20# osm-charmers@lists.launchpad.net 

21## 

22 

23import logging 

24from typing import Any, Dict, List, NoReturn 

25 

26logger = logging.getLogger(__name__) 

27 

28 

29def _validate_data( 

30 config_data: Dict[str, Any], relation_data: Dict[str, Any] 

31) -> NoReturn: 

32 """Validate input data. 

33 

34 Args: 

35 config_data (Dict[str, Any]): configuration data. 

36 relation_data (Dict[str, Any]): relation data. 

37 """ 

38 config_validators = { 

39 "log_level": lambda value, _: ( 

40 isinstance(value, str) and value in ("INFO", "DEBUG") 

41 ), 

42 } 

43 relation_validators = { 

44 "message_host": lambda value, _: isinstance(value, str) and len(value) > 0, 

45 "message_port": lambda value, _: isinstance(value, int) and value > 0, 

46 "database_uri": lambda value, _: ( 

47 isinstance(value, str) and value.startswith("mongodb://") 

48 ), 

49 } 

50 problems = [] 

51 

52 for key, validator in config_validators.items(): 

53 valid = validator(config_data.get(key), config_data) 

54 

55 if not valid: 

56 problems.append(key) 

57 

58 for key, validator in relation_validators.items(): 

59 valid = validator(relation_data.get(key), relation_data) 

60 

61 if not valid: 

62 problems.append(key) 

63 

64 if len(problems) > 0: 

65 raise ValueError("Errors found in: {}".format(", ".join(problems))) 

66 

67 

68def _make_pod_ports(port: int) -> List[Dict[str, Any]]: 

69 """Generate pod ports details. 

70 

71 Args: 

72 port (int): port to expose. 

73 

74 Returns: 

75 List[Dict[str, Any]]: pod port details. 

76 """ 

77 return [{"name": "pol", "containerPort": port, "protocol": "TCP"}] 

78 

79 

80def _make_pod_envconfig( 

81 config: Dict[str, Any], relation_state: Dict[str, Any] 

82) -> Dict[str, Any]: 

83 """Generate pod environment configuration. 

84 

85 Args: 

86 config (Dict[str, Any]): configuration information. 

87 relation_state (Dict[str, Any]): relation state information. 

88 

89 Returns: 

90 Dict[str, Any]: pod environment configuration. 

91 """ 

92 envconfig = { 

93 # General configuration 

94 "ALLOW_ANONYMOUS_LOGIN": "yes", 

95 "OSMPOL_GLOBAL_LOGLEVEL": config["log_level"], 

96 # Kafka configuration 

97 "OSMPOL_MESSAGE_HOST": relation_state["message_host"], 

98 "OSMPOL_MESSAGE_DRIVER": "kafka", 

99 "OSMPOL_MESSAGE_PORT": relation_state["message_port"], 

100 # Database configuration 

101 "OSMPOL_DATABASE_DRIVER": "mongo", 

102 "OSMPOL_DATABASE_URI": relation_state["database_uri"], 

103 } 

104 

105 return envconfig 

106 

107 

108def _make_startup_probe() -> Dict[str, Any]: 

109 """Generate startup probe. 

110 

111 Returns: 

112 Dict[str, Any]: startup probe. 

113 """ 

114 return { 

115 "exec": {"command": ["/usr/bin/pgrep", "python3"]}, 

116 "initialDelaySeconds": 60, 

117 "timeoutSeconds": 5, 

118 } 

119 

120 

121def _make_readiness_probe() -> Dict[str, Any]: 

122 """Generate readiness probe. 

123 

124 Returns: 

125 Dict[str, Any]: readiness probe. 

126 """ 

127 return { 

128 "exec": { 

129 "command": ["sh", "-c", "osm-pol-healthcheck || exit 1"], 

130 }, 

131 "periodSeconds": 10, 

132 "timeoutSeconds": 5, 

133 "successThreshold": 1, 

134 "failureThreshold": 3, 

135 } 

136 

137 

138def _make_liveness_probe() -> Dict[str, Any]: 

139 """Generate liveness probe. 

140 

141 Returns: 

142 Dict[str, Any]: liveness probe. 

143 """ 

144 return { 

145 "exec": { 

146 "command": ["sh", "-c", "osm-pol-healthcheck || exit 1"], 

147 }, 

148 "initialDelaySeconds": 45, 

149 "periodSeconds": 10, 

150 "timeoutSeconds": 5, 

151 "successThreshold": 1, 

152 "failureThreshold": 3, 

153 } 

154 

155 

156def make_pod_spec( 

157 image_info: Dict[str, str], 

158 config: Dict[str, Any], 

159 relation_state: Dict[str, Any], 

160 app_name: str = "pol", 

161 port: int = 80, 

162) -> Dict[str, Any]: 

163 """Generate the pod spec information. 

164 

165 Args: 

166 image_info (Dict[str, str]): Object provided by 

167 OCIImageResource("image").fetch(). 

168 config (Dict[str, Any]): Configuration information. 

169 relation_state (Dict[str, Any]): Relation state information. 

170 app_name (str, optional): Application name. Defaults to "pol". 

171 port (int, optional): Port for the container. Defaults to 80. 

172 

173 Returns: 

174 Dict[str, Any]: Pod spec dictionary for the charm. 

175 """ 

176 if not image_info: 

177 return None 

178 

179 _validate_data(config, relation_state) 

180 

181 ports = _make_pod_ports(port) 

182 env_config = _make_pod_envconfig(config, relation_state) 

183 

184 return { 

185 "version": 3, 

186 "containers": [ 

187 { 

188 "name": app_name, 

189 "imageDetails": image_info, 

190 "imagePullPolicy": "Always", 

191 "ports": ports, 

192 "envConfig": env_config, 

193 } 

194 ], 

195 "kubernetesResources": { 

196 "ingressResources": [], 

197 }, 

198 }