blob: 5a313b79b8ad63b74b5197ce83882c6b152555f0 [file] [log] [blame]
Peter Pentchev469dfea2022-06-27 12:48:18 +03001#! /usr/bin/env python3
2
Biser Milanov81bdc462022-09-14 10:28:45 +03003# Copyright 2022 StorPool
Peter Pentchev469dfea2022-06-27 12:48:18 +03004#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
Biser Milanov80c39912022-09-07 13:03:34 +030017"""A StorPool backend charm for Cinder"""
18
Biser Milanov20d50602022-08-09 17:16:36 +030019import dataclasses
Biser Milanov2afeb432022-08-05 10:42:40 +030020import logging
Biser Milanov20d50602022-08-09 17:16:36 +030021import pathlib
Peter Pentchev469dfea2022-06-27 12:48:18 +030022
Peter Pentchev469dfea2022-06-27 12:48:18 +030023from ops.main import main
Biser Milanov2afeb432022-08-05 10:42:40 +030024from ops.model import BlockedStatus
Biser Milanov80c39912022-09-07 13:03:34 +030025from ops_openstack.core import charm_class, get_charm_class
26from ops_openstack.plugins.classes import CinderStoragePluginCharm
Biser Milanov2afeb432022-08-05 10:42:40 +030027
28logger = logging.getLogger(__name__)
Peter Pentchev469dfea2022-06-27 12:48:18 +030029
30
Biser Milanov20d50602022-08-09 17:16:36 +030031@dataclasses.dataclass(frozen=True)
32class StorPoolConfItems:
Biser Milanov5f47c472022-09-02 17:17:56 +030033 """
34 'Serialize' StorPool configuration items depending on the target file format
35 """
36
Biser Milanov20d50602022-08-09 17:16:36 +030037 sp_api_http_host: str
38 sp_api_http_port: str
39 sp_auth_token: str
40
Peter Pentchev28fea782022-08-23 01:07:37 +030041 @classmethod
42 def from_config(cls, data) -> "StorPoolConfItems":
Biser Milanov80c39912022-09-07 13:03:34 +030043 """Create an object from an options dictionary"""
Peter Pentchev28fea782022-08-23 01:07:37 +030044 args = {
45 field.name: str(data[field.name.replace("_", "-")]) for field in dataclasses.fields(cls)
46 }
47 return cls(**args)
48
Biser Milanov20d50602022-08-09 17:16:36 +030049 def to_ini_key_value_pairs(self) -> str:
Biser Milanov80c39912022-09-07 13:03:34 +030050 """Serialize to ini-style key-value pairs"""
Biser Milanov20d50602022-08-09 17:16:36 +030051 return "".join(
52 f"{name.upper()}={value}\n" for name, value in dataclasses.asdict(self).items()
53 )
54
55
Peter Pentchev469dfea2022-06-27 12:48:18 +030056class CinderCharmBase(CinderStoragePluginCharm):
Biser Milanov80c39912022-09-07 13:03:34 +030057 """
58 Base class for the StorPool charm
59 """
Peter Pentchev469dfea2022-06-27 12:48:18 +030060
Biser Milanov8bc000b2022-08-08 14:39:29 +030061 PACKAGES = ["charm-cinder-storpool-deps", "cinder-common"]
Biser Milanov4ea59212022-08-05 11:03:05 +030062 MANDATORY_CONFIG = [
63 "protocol",
64 "storpool-template",
65 "sp-api-http-host",
66 "sp-api-http-port",
67 "sp-auth-token",
Peter Pentchev38a6aa52022-08-23 01:17:17 +030068 "iscsi-portal-group",
Biser Milanov4ea59212022-08-05 11:03:05 +030069 ]
Peter Pentchev469dfea2022-06-27 12:48:18 +030070 # Overriden from the parent. May be set depending on the charm's properties
71 stateless = True
72 active_active = True
73
Biser Milanov2afeb432022-08-05 10:42:40 +030074 def on_config(self, event):
75 config = dict(self.framework.model.config)
76 conf_error = self._check_for_config_errors(config)
77 if conf_error is not None:
78 logger.error(conf_error)
79 self.unit.status = BlockedStatus(conf_error)
Biser Milanov57725c22022-08-16 15:59:41 +030080 self._stored.is_started = False
81
Biser Milanov2afeb432022-08-05 10:42:40 +030082 return
83
Biser Milanovfd3f55d2022-09-02 17:09:59 +030084 create_storpool_conf(StorPoolConfItems.from_config(config))
Biser Milanov20d50602022-08-09 17:16:36 +030085
Biser Milanov2afeb432022-08-05 10:42:40 +030086 super().on_config(event)
87
Biser Milanov57725c22022-08-16 15:59:41 +030088 self._stored.is_started = True
89
Biser Milanov80c39912022-09-07 13:03:34 +030090 def custom_status_check(self):
91 """Overriding abstract, which is not used anywhere"""
92 return BlockedStatus("Should not be here")
93
94 def cinder_configuration(self, charm_config):
95 conf_error = self._check_for_config_errors(charm_config)
Biser Milanov2afeb432022-08-05 10:42:40 +030096 if conf_error is not None:
97 logger.error(conf_error)
Biser Milanov57725c22022-08-16 15:59:41 +030098 self._stored.is_started = False
99
Biser Milanov2afeb432022-08-05 10:42:40 +0300100 return []
101
Peter Pentchev469dfea2022-06-27 12:48:18 +0300102 # Return the configuration to be set by the principal.
Biser Milanov80c39912022-09-07 13:03:34 +0300103 backend_name = charm_config.get("volume-backend-name", self.framework.model.app.name)
Biser Milanov53644f62022-08-03 16:08:59 +0300104 volume_driver = "cinder.volume.drivers.storpool.StorPoolDriver"
Biser Milanov2afeb432022-08-05 10:42:40 +0300105
Peter Pentchev469dfea2022-06-27 12:48:18 +0300106 options = [
Biser Milanov53644f62022-08-03 16:08:59 +0300107 ("volume_driver", volume_driver),
108 ("volume_backend_name", backend_name),
Biser Milanov80c39912022-09-07 13:03:34 +0300109 ("storpool_template", charm_config["storpool-template"]),
110 ("sp_api_http_host", charm_config["sp-api-http-host"]),
111 ("sp_api_http_port", charm_config["sp-api-http-port"]),
112 ("sp_auth_token", charm_config["sp-auth-token"]),
Peter Pentchev38a6aa52022-08-23 01:17:17 +0300113 ("iscsi_export_to", "*"),
Biser Milanov80c39912022-09-07 13:03:34 +0300114 ("iscsi_portal_group", charm_config["iscsi-portal-group"]),
Peter Pentchev469dfea2022-06-27 12:48:18 +0300115 ]
116
Biser Milanov80c39912022-09-07 13:03:34 +0300117 if charm_config.get("use-multipath"):
Biser Milanov53644f62022-08-03 16:08:59 +0300118 options.extend(
119 [
120 ("use_multipath_for_image_xfer", True),
121 ("enforce_multipath_for_image_xfer", True),
122 ]
123 )
Peter Pentchev469dfea2022-06-27 12:48:18 +0300124
Biser Milanov80c39912022-09-07 13:03:34 +0300125 create_storpool_conf(StorPoolConfItems.from_config(charm_config))
Biser Milanov20d50602022-08-09 17:16:36 +0300126
Biser Milanov57725c22022-08-16 15:59:41 +0300127 self._stored.is_started = True
128
Peter Pentchev469dfea2022-06-27 12:48:18 +0300129 return options
130
Biser Milanovfd3f55d2022-09-02 17:09:59 +0300131 def _check_for_config_errors(self, config):
132 missing = []
133 for mandatory in self.MANDATORY_CONFIG:
134 if mandatory not in config:
135 missing.append(mandatory)
136
137 if missing:
138 return f"Mandatory options are missing: {', '.join(missing)}"
139
140 if config["protocol"] not in ["block", "iscsi"]:
141 return (
142 f"""Invalid 'protocol' option provided: '{config["protocol"]}';"""
143 "valid are 'block' and 'iscsi'"
144 )
145
146 if config["protocol"] == "block":
147 return "'protocol' value 'block' not yet supported"
148
Biser Milanov80c39912022-09-07 13:03:34 +0300149 if not 0 < config["sp-api-http-port"] < 65536:
Biser Milanovfd3f55d2022-09-02 17:09:59 +0300150 return (
151 f"""'sp-api-http-port' ('{config["sp-api-http-port"]}')"""
152 "is not a valid port (0-65535)"
153 )
Biser Milanov20d50602022-08-09 17:16:36 +0300154
Biser Milanov80c39912022-09-07 13:03:34 +0300155 return None
156
Peter Pentchev469dfea2022-06-27 12:48:18 +0300157
158@charm_class
159class CinderStorPoolCharm(CinderCharmBase):
Biser Milanov80c39912022-09-07 13:03:34 +0300160 """
161 Actual class for the StorPool charm
162 """
163
Biser Milanov53644f62022-08-03 16:08:59 +0300164 release = "yoga"
Peter Pentchev469dfea2022-06-27 12:48:18 +0300165
166
Biser Milanovfd3f55d2022-09-02 17:09:59 +0300167def create_storpool_conf(sp_conf_items: StorPoolConfItems):
Biser Milanov80c39912022-09-07 13:03:34 +0300168 """Generate a storpool.conf with the provided options"""
Biser Milanovfd3f55d2022-09-02 17:09:59 +0300169 pathlib.Path("/etc/storpool.conf").write_text(
170 "# Do not edit; this file is generated by the cinder-storpool charm.\n"
171 + sp_conf_items.to_ini_key_value_pairs(),
172 encoding="UTF-8",
173 )
174
175
Biser Milanov53644f62022-08-03 16:08:59 +0300176if __name__ == "__main__":
Peter Pentchev3a17d7d2022-07-27 13:11:57 +0000177 # main(get_charm_class_for_release())
Peter Pentcheva8266902022-07-29 05:55:35 +0000178 # main(CinderStorPoolCharm)
179 main(get_charm_class(release="yoga"))