Skip to content

Commit a1698d5

Browse files
MOS CIGerrit Code Review
MOS CI
authored and
Gerrit Code Review
committed
Merge "Handle exporter tls public secret"
2 parents 0b2ecbe + e038456 commit a1698d5

File tree

7 files changed

+94
-28
lines changed

7 files changed

+94
-28
lines changed

charts/rockoon/templates/exporter.yaml

+8
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,19 @@ spec:
110110
mountPath: /etc/openstack/
111111
- name: exporter-etc
112112
mountPath: /etc/rockoon/exporter
113+
- name: ca-cert
114+
mountPath: /usr/local/share/ca-certificates/osdpl/
115+
readOnly: true
113116
volumes:
114117
- name: os-clouds
115118
secret:
116119
secretName: keystone-os-clouds
117120
defaultMode: 365
121+
- name: ca-cert
122+
secret:
123+
secretName: exporter-ca-cert
124+
optional: true
125+
defaultMode: 420
118126
- name: exporter-etc
119127
secret:
120128
secretName: {{ include "rockoon.fullname" . }}-exporter-etc

rockoon/constants.py

+2
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ class K8sObjHealth(enum.Enum):
159159

160160
COMPUTE_NODE_CONTROLLER_SECRET_NAME = "keystone-os-clouds"
161161
LIBVIRT_SERVER_TLS_SECRET_NAME = "libvirt-server-tls"
162+
EXPORTER_CA_CERT_SECRET_NAME = "exporter-ca-cert"
163+
EXPORTER_NAMESPACE = "osh-system"
162164

163165
SLURP_RELEASES = ["yoga", "antelope", "caracal"]
164166

rockoon/controllers/secrets.py

+36
Original file line numberDiff line numberDiff line change
@@ -518,3 +518,39 @@ def handle_keystone_osclouds_secret(
518518
}
519519

520520
secrets.ExternalCredentialSecret("identity").save(encoded_ext_data)
521+
522+
523+
@kopf.on.create(
524+
"",
525+
"v1",
526+
"secrets",
527+
when=lambda name, **_: "keystone-tls-public" in name,
528+
)
529+
@kopf.on.resume(
530+
"",
531+
"v1",
532+
"secrets",
533+
when=lambda name, **_: "keystone-tls-public" in name,
534+
)
535+
@kopf.on.update(
536+
"",
537+
"v1",
538+
"secrets",
539+
when=lambda name, **_: "keystone-tls-public" in name,
540+
)
541+
def handle_exporter_ca_cert_secret(
542+
body,
543+
meta,
544+
name,
545+
status,
546+
logger,
547+
diff,
548+
**kwargs,
549+
):
550+
LOG.debug(f"Handling secret create/update {name}")
551+
552+
utils.log_changes(kwargs.get("old", {}), kwargs.get("new", {}))
553+
554+
ca_data = body["data"]["ca.crt"]
555+
secret_data = {"ca.crt": ca_data}
556+
secrets.ExporterCaCertSecret().save(secret_data)

rockoon/exporter/collectors/openstack/api.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from prometheus_client.core import GaugeMetricFamily
2121

2222
from rockoon import utils
23+
from rockoon.exporter import settings
2324
from rockoon.exporter.collectors.openstack import base
2425

2526

@@ -28,12 +29,16 @@
2829

2930
def check_endpoint(url, service_type, service_name, headers):
3031
result = {"success": True}
31-
# TODO(vsaienko): mount ssl ca_cert from osdpl and use here.
3232
try:
3333
requests.packages.urllib3.disable_warnings(
3434
category=InsecureRequestWarning
3535
)
36-
resp = requests.get(url, timeout=10, verify=False, headers=headers)
36+
resp = requests.get(
37+
url,
38+
timeout=10,
39+
verify=settings.OSCTL_EXPORTER_CA_CERT_PATH,
40+
headers=headers,
41+
)
3742
if resp.status_code >= 500:
3843
LOG.warning(
3944
f"Got bad responce code {resp.status_code} from {url}."

rockoon/exporter/collectors/openstack/horizon.py

+29-26
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1212
# License for the specific language governing permissions and limitations
1313
# under the License.
14+
import hashlib
1415
import html.parser
1516
import http.cookiejar
1617
import ssl
@@ -22,6 +23,7 @@
2223
from prometheus_client.core import GaugeMetricFamily
2324

2425
from rockoon import utils
26+
from rockoon.exporter import settings
2527
from rockoon.exporter.collectors.openstack import base
2628

2729
LOG = utils.get_logger(__name__)
@@ -68,7 +70,8 @@ class OsdplHorizonMetricCollector(base.OpenStackBaseMetricCollector):
6870
is_service_available = True
6971

7072
def __init__(self):
71-
self.opener = None
73+
self._opener = None
74+
self.ca_cert_checksum = None
7275
self.cookie_jar = http.cookiejar.CookieJar()
7376
super().__init__()
7477

@@ -109,19 +112,17 @@ def dashboard_url(self):
109112
public_domain_name = self.osdpl.mspec["public_domain_name"]
110113
return f"https://horizon.{public_domain_name}/"
111114

112-
def check_login_page(self, dashboard_url, timeout=10):
115+
def check_login_page(self, opener, dashboard_url, timeout=10):
113116
start_time = perf_counter()
114-
response = (
115-
self._get_opener().open(dashboard_url, timeout=timeout).read()
116-
)
117+
response = opener.open(dashboard_url, timeout=timeout).read()
117118
if "id_username" not in response.decode("utf-8"):
118119
raise ValueError("Cannot find 'id_username' in login page")
119120
end_time = perf_counter()
120121
return end_time - start_time
121122

122-
def check_user_login(self, dashboard_url, credentials, timeout=10):
123+
def check_user_login(self, opener, dashboard_url, credentials, timeout=10):
123124
start_time = perf_counter()
124-
response = self._get_opener().open(dashboard_url).read()
125+
response = opener.open(dashboard_url).read()
125126

126127
# Grab the CSRF token and default region
127128
parser = HorizonHTMLParser()
@@ -143,39 +144,41 @@ def check_user_login(self, dashboard_url, credentials, timeout=10):
143144
"domain": credentials["user_domain_name"],
144145
"csrfmiddlewaretoken": parser.csrf_token,
145146
}
146-
self._get_opener().open(
147-
req, parse.urlencode(params).encode(), timeout=timeout
148-
)
147+
opener.open(req, parse.urlencode(params).encode(), timeout=timeout)
149148

150-
response = (
151-
self._get_opener().open(dashboard_url, timeout=timeout).read()
152-
)
149+
response = opener.open(dashboard_url, timeout=timeout).read()
153150
if "Overview" not in response.decode("utf-8"):
154151
raise ValueError("Cannot find 'Overview' in home page")
155152
end_time = perf_counter()
156153
return end_time - start_time
157154

158-
def _get_opener(self):
159-
if not self.opener:
160-
# TODO(dbiletskyi): add ssl verify here
161-
ctx = ssl.create_default_context()
162-
ctx.check_hostname = False
163-
ctx.verify_mode = ssl.CERT_NONE
164-
self.opener = request.build_opener(
165-
request.HTTPSHandler(context=ctx),
166-
request.HTTPCookieProcessor(self.cookie_jar),
167-
)
168-
return self.opener
155+
@property
156+
def opener(self):
157+
with open(settings.OSCTL_EXPORTER_CA_CERT_PATH, "rb") as f:
158+
current_checksum = hashlib.sha256(f.read()).hexdigest()
159+
if self.ca_cert_checksum == current_checksum and self._opener:
160+
return self._opener
161+
162+
self.ca_cert_checksum = current_checksum
163+
ctx = ssl.create_default_context(
164+
cafile=settings.OSCTL_EXPORTER_CA_CERT_PATH
165+
)
166+
self._opener = request.build_opener(
167+
request.HTTPSHandler(context=ctx),
168+
request.HTTPCookieProcessor(self.cookie_jar),
169+
)
170+
return self._opener
169171

170172
@utils.timeit
171173
def update_login_samples(self):
172174
login_success_status = 0
173175
login_latency_samples = []
174176
try:
175177
self.cookie_jar.clear()
178+
opener = self.opener
176179
credentials = self.get_credentials()
177180
dashboard_url = self.dashboard_url
178-
login_page_latency = self.check_login_page(dashboard_url)
181+
login_page_latency = self.check_login_page(opener, dashboard_url)
179182
login_latency_samples.append(
180183
(
181184
[
@@ -186,7 +189,7 @@ def update_login_samples(self):
186189
)
187190
)
188191
login_success_latency = self.check_user_login(
189-
dashboard_url, credentials
192+
opener, dashboard_url, credentials
190193
)
191194
login_latency_samples.append(
192195
(

rockoon/exporter/settings.py

+5
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,8 @@
3333
# Number of seconds we can wait for polling tasks before return cached result
3434
# Should be lover than prometheus scrape_timeout which is 1m by default.
3535
OSCTL_SCRAPE_TIMEOUT = int(os.getenv("OSCTL_SCRAPE_TIMEOUT", "45"))
36+
37+
OSCTL_EXPORTER_CA_CERT_PATH = os.getenv(
38+
"OSCTL_EXPORTER_CA_CERT_PATH",
39+
"/usr/local/share/ca-certificates/osdpl/ca.crt",
40+
)

rockoon/secrets.py

+7
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,13 @@ def __init__(
12091209
self.secret_name = f"openstack-{name}-credentials"
12101210

12111211

1212+
class ExporterCaCertSecret(SecretCopy):
1213+
secret_name = constants.EXPORTER_CA_CERT_SECRET_NAME
1214+
1215+
def __init__(self, namespace=constants.EXPORTER_NAMESPACE):
1216+
super().__init__(namespace)
1217+
1218+
12121219
@dataclass
12131220
class OpenStackIAMData:
12141221
clientId: str

0 commit comments

Comments
 (0)