2 # Copyright 2020 Canonical Ltd.
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
8 # http://www.apache.org/licenses/LICENSE-2.0
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.
19 from pathlib
import Path
20 from string
import Template
23 from ops
.charm
import CharmBase
24 from ops
.framework
import StoredState
, Object
25 from ops
.main
import main
26 from ops
.model
import (
35 logger
= logging
.getLogger(__name__
)
38 class NGUICharm(CharmBase
):
41 def __init__(self
, framework
, key
):
42 super().__init
__(framework
, key
)
43 self
.state
.set_default(spec
=None)
44 self
.state
.set_default(nbi_host
=None)
45 self
.state
.set_default(nbi_port
=None)
47 # Observe Charm related events
48 self
.framework
.observe(self
.on
.config_changed
, self
.on_config_changed
)
49 self
.framework
.observe(self
.on
.start
, self
.on_start
)
50 self
.framework
.observe(self
.on
.upgrade_charm
, self
.on_upgrade_charm
)
51 self
.framework
.observe(
52 self
.on
.nbi_relation_changed
, self
.on_nbi_relation_changed
55 # SSL Certificate path
56 self
.ssl_folder
= "/certs"
57 self
.ssl_crt_name
= "ssl_certificate.crt"
58 self
.ssl_key_name
= "ssl_certificate.key"
60 def _apply_spec(self
):
61 # Only apply the spec if this unit is a leader.
62 unit
= self
.model
.unit
63 if not unit
.is_leader():
64 unit
.status
= ActiveStatus("ready")
66 if not self
.state
.nbi_host
or not self
.state
.nbi_port
:
67 unit
.status
= WaitingStatus("Waiting for NBI")
69 unit
.status
= MaintenanceStatus("Applying new pod spec")
71 new_spec
= self
.make_pod_spec()
72 if new_spec
== self
.state
.spec
:
73 unit
.status
= ActiveStatus("ready")
75 self
.framework
.model
.pod
.set_spec(new_spec
)
76 self
.state
.spec
= new_spec
77 unit
.status
= ActiveStatus("ready")
79 def make_pod_spec(self
):
80 config
= self
.framework
.model
.config
83 "http_port": config
["port"],
84 "https_port": config
["https_port"],
85 "server_name": config
["server_name"],
86 "client_max_body_size": config
["client_max_body_size"],
87 "nbi_host": self
.state
.nbi_host
or config
["nbi_host"],
88 "nbi_port": self
.state
.nbi_port
or config
["nbi_port"],
93 ssl_certificate
= None
94 ssl_certificate_key
= None
97 if "ssl_certificate" in config
and "ssl_certificate_key" in config
:
98 # Get bytes of cert and key
99 cert_b
= base64
.b64decode(config
["ssl_certificate"])
100 key_b
= base64
.b64decode(config
["ssl_certificate_key"])
101 # Decode key and cert
102 ssl_certificate
= cert_b
.decode("utf-8")
103 ssl_certificate_key
= key_b
.decode("utf-8")
105 cert_path
= "{}/{}".format(self
.ssl_folder
, self
.ssl_crt_name
)
106 key_path
= "{}/{}".format(self
.ssl_folder
, self
.ssl_key_name
)
108 config_spec
["port"] = "{} ssl".format(config
["https_port"])
109 config_spec
["ssl_crt"] = "ssl_certificate {};".format(cert_path
)
110 config_spec
["ssl_crt_key"] = "ssl_certificate_key {};".format(key_path
)
113 config_spec
["ssl_crt"] = ""
114 config_spec
["ssl_crt_key"] = ""
118 "name": "configuration",
119 "mountPath": "/etc/nginx/sites-available/",
122 .name
: Template(Path(filename
).read_text())
123 .substitute(config_spec
)
124 for filename
in glob("files/*")
128 port
= config
["https_port"] if ssl_enabled
else config
["port"]
132 "containerPort": port
,
139 "tcpSocket": {"port": port
},
142 "initialDelaySeconds": 10,
145 "tcpSocket": {"port": port
},
147 "initialDelaySeconds": 45,
151 if ssl_certificate
and ssl_certificate_key
:
155 "mountPath": self
.ssl_folder
,
157 self
.ssl_crt_name
: ssl_certificate
,
158 self
.ssl_key_name
: ssl_certificate_key
,
169 "name": self
.framework
.model
.app
.name
,
171 "imagePath": config
["image"],
172 "username": config
["image_username"],
173 "password": config
["image_password"],
176 "kubernetes": kubernetes
,
184 def on_config_changed(self
, event
):
185 """Handle changes in configuration"""
188 def on_start(self
, event
):
189 """Called when the charm is being installed"""
192 def on_upgrade_charm(self
, event
):
193 """Upgrade the charm."""
194 unit
= self
.model
.unit
195 unit
.status
= MaintenanceStatus("Upgrading charm")
198 def on_nbi_relation_changed(self
, event
):
199 nbi_host
= event
.relation
.data
[event
.unit
].get("host")
200 nbi_port
= event
.relation
.data
[event
.unit
].get("port")
201 if nbi_host
and self
.state
.nbi_host
!= nbi_host
:
202 self
.state
.nbi_host
= nbi_host
203 if nbi_port
and self
.state
.nbi_port
!= nbi_port
:
204 self
.state
.nbi_port
= nbi_port
208 if __name__
== "__main__":