5c9182a5761a6af3c32756b0f62dbdde56ee9c47
[osm/devops.git] / installers / charm / mon / src / pod_spec.py
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
23 import logging
24 from pydantic import BaseModel, constr, PositiveInt
25 from typing import Any, Dict, List
26
27 logger = logging.getLogger(__name__)
28
29
30 class ConfigData(BaseModel):
31 """Configuration data model."""
32
33 openstack_default_granularity: PositiveInt
34 global_request_timeout: PositiveInt
35 log_level: constr(regex=r"^(INFO|DEBUG)$")
36 collector_interval: PositiveInt
37 evaluator_interval: PositiveInt
38 database_commonkey: constr(min_length=1)
39 vca_host: constr(min_length=1)
40 vca_user: constr(min_length=1)
41 vca_password: constr(min_length=1)
42 vca_cacert: str
43
44
45 class RelationData(BaseModel):
46 """Relation data model."""
47
48 message_host: constr(min_length=1)
49 message_port: PositiveInt
50 database_uri: constr(regex=r"^(mongodb://)")
51 prometheus_host: constr(min_length=1)
52 prometheus_port: PositiveInt
53
54
55 def _make_pod_ports(port: int) -> List[Dict[str, Any]]:
56 """Generate pod ports details.
57
58 Args:
59 port (int): port to expose.
60
61 Returns:
62 List[Dict[str, Any]]: pod port details.
63 """
64 return [{"name": "mon", "containerPort": port, "protocol": "TCP"}]
65
66
67 def _make_pod_envconfig(
68 config: Dict[str, Any], relation_state: Dict[str, Any]
69 ) -> Dict[str, Any]:
70 """Generate pod environment configuration.
71
72 Args:
73 config (Dict[str, Any]): configuration information.
74 relation_state (Dict[str, Any]): relation state information.
75
76 Returns:
77 Dict[str, Any]: pod environment configuration.
78 """
79 envconfig = {
80 # General configuration
81 "ALLOW_ANONYMOUS_LOGIN": "yes",
82 "OSMMON_OPENSTACK_DEFAULT_GRANULARITY": config["openstack_default_granularity"],
83 "OSMMON_GLOBAL_REQUEST_TIMEOUT": config["global_request_timeout"],
84 "OSMMON_GLOBAL_LOGLEVEL": config["log_level"],
85 "OSMMON_COLLECTOR_INTERVAL": config["collector_interval"],
86 "OSMMON_EVALUATOR_INTERVAL": config["evaluator_interval"],
87 # Kafka configuration
88 "OSMMON_MESSAGE_DRIVER": "kafka",
89 "OSMMON_MESSAGE_HOST": relation_state["message_host"],
90 "OSMMON_MESSAGE_PORT": relation_state["message_port"],
91 # Database configuration
92 "OSMMON_DATABASE_DRIVER": "mongo",
93 "OSMMON_DATABASE_URI": relation_state["database_uri"],
94 "OSMMON_DATABASE_COMMONKEY": config["database_commonkey"],
95 # Prometheus configuration
96 "OSMMON_PROMETHEUS_URL": f"http://{relation_state['prometheus_host']}:{relation_state['prometheus_port']}",
97 # VCA configuration
98 "OSMMON_VCA_HOST": config["vca_host"],
99 "OSMMON_VCA_USER": config["vca_user"],
100 "OSMMON_VCA_SECRET": config["vca_password"],
101 "OSMMON_VCA_CACERT": config["vca_cacert"],
102 }
103
104 return envconfig
105
106
107 def _make_startup_probe() -> Dict[str, Any]:
108 """Generate startup probe.
109
110 Returns:
111 Dict[str, Any]: startup probe.
112 """
113 return {
114 "exec": {"command": ["/usr/bin/pgrep python3"]},
115 "initialDelaySeconds": 60,
116 "timeoutSeconds": 5,
117 }
118
119
120 def _make_readiness_probe(port: int) -> Dict[str, Any]:
121 """Generate readiness probe.
122
123 Args:
124 port (int): [description]
125
126 Returns:
127 Dict[str, Any]: readiness probe.
128 """
129 return {
130 "tcpSocket": {
131 "port": port,
132 },
133 "periodSeconds": 10,
134 "timeoutSeconds": 5,
135 "successThreshold": 1,
136 "failureThreshold": 3,
137 }
138
139
140 def _make_liveness_probe(port: int) -> Dict[str, Any]:
141 """Generate liveness probe.
142
143 Args:
144 port (int): [description]
145
146 Returns:
147 Dict[str, Any]: liveness probe.
148 """
149 return {
150 "tcpSocket": {
151 "port": port,
152 },
153 "initialDelaySeconds": 45,
154 "periodSeconds": 10,
155 "timeoutSeconds": 5,
156 "successThreshold": 1,
157 "failureThreshold": 3,
158 }
159
160
161 def make_pod_spec(
162 image_info: Dict[str, str],
163 config: Dict[str, Any],
164 relation_state: Dict[str, Any],
165 app_name: str = "mon",
166 port: int = 8000,
167 ) -> Dict[str, Any]:
168 """Generate the pod spec information.
169
170 Args:
171 image_info (Dict[str, str]): Object provided by
172 OCIImageResource("image").fetch().
173 config (Dict[str, Any]): Configuration information.
174 relation_state (Dict[str, Any]): Relation state information.
175 app_name (str, optional): Application name. Defaults to "mon".
176 port (int, optional): Port for the container. Defaults to 8000.
177
178 Returns:
179 Dict[str, Any]: Pod spec dictionary for the charm.
180 """
181 if not image_info:
182 return None
183
184 ConfigData(**(config))
185 RelationData(**(relation_state))
186
187 ports = _make_pod_ports(port)
188 env_config = _make_pod_envconfig(config, relation_state)
189
190 return {
191 "version": 3,
192 "containers": [
193 {
194 "name": app_name,
195 "imageDetails": image_info,
196 "imagePullPolicy": "Always",
197 "ports": ports,
198 "envConfig": env_config,
199 }
200 ],
201 "kubernetesResources": {
202 "ingressResources": [],
203 },
204 }