Skip to content

Commit 88d96ea

Browse files
committed
Update Notifications integration to be compatible w/ version 0.2.0
1 parent a0ca2e2 commit 88d96ea

6 files changed

Lines changed: 229 additions & 151 deletions

File tree

application/controllers/ConfigController.php

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Icinga\Module\Kubernetes\Controllers;
66

7+
use Exception;
78
use GuzzleHttp\Psr7\ServerRequest;
89
use Icinga\Application\Config;
910
use Icinga\Application\Logger;
@@ -22,7 +23,6 @@
2223
use ipl\Sql\Connection;
2324
use ipl\Stdlib\Filter;
2425
use ipl\Web\Url;
25-
use LogicException;
2626
use Ramsey\Uuid\Uuid;
2727
use Throwable;
2828

@@ -44,7 +44,7 @@ public function databaseAction(): void
4444
$config = Config::module('kubernetes');
4545
$form = (new DatabaseConfigForm())
4646
->populate($config->getSection('database'))
47-
->on(DatabaseConfigForm::ON_SUCCESS, function (DatabaseConfigForm $form) use ($config) {
47+
->on(DatabaseConfigForm::ON_SUBMIT, function (DatabaseConfigForm $form) use ($config) {
4848
$config->setSection('database', $form->getValues());
4949
$config->saveIni();
5050

@@ -68,6 +68,24 @@ public function hasBeenSubmitted(): bool
6868
{
6969
return true;
7070
}
71+
72+
public function onError()
73+
{
74+
$messages = [];
75+
foreach ($this->getMessages() as $message) {
76+
if ($message instanceof Throwable) {
77+
$messages[] = $message->getMessage();
78+
} else {
79+
$messages[] = $message;
80+
}
81+
}
82+
foreach ($this->getElements() as $element) {
83+
foreach ($element->getMessages() as $message) {
84+
$messages[] = $element->getName() . ": " . $message;
85+
}
86+
}
87+
throw new Exception(implode("\n", array_filter($messages)));
88+
}
7189
};
7290

7391
$form = (new NotificationsConfigForm())
@@ -79,7 +97,7 @@ public function hasBeenSubmitted(): bool
7997
->get('cluster_uuid')
8098
])
8199
->on(
82-
NotificationsConfigForm::ON_SUCCESS,
100+
NotificationsConfigForm::ON_SUBMIT,
83101
function (NotificationsConfigForm $form) use ($sourceForm) {
84102
if ($form->isLocked()) {
85103
$form->addMessage($this->translate('Notifications configuration is locked.'));
@@ -101,7 +119,7 @@ function (NotificationsConfigForm $form) use ($sourceForm) {
101119

102120
if (
103121
$source === null
104-
// Must be kept in sync with SourceForm:292.
122+
// Must be kept in sync with SourceForm.
105123
|| password_hash(
106124
$kconfig[KConfig::NOTIFICATIONS_PASSWORD]->value,
107125
SourceForm::HASH_ALGORITHM
@@ -110,20 +128,6 @@ function (NotificationsConfigForm $form) use ($sourceForm) {
110128
try {
111129
$values[KConfig::NOTIFICATIONS_PASSWORD] = $this
112130
->createOrUpdateSource($sourceForm, $clusterUuid);
113-
114-
/** @var ?Source $source */
115-
$source = Source::on(NotificationsDatabase::get())
116-
->filter(Filter::all(
117-
Filter::equal('name', KConfig::DEFAULT_NOTIFICATIONS_NAME . " ($clusterUuid)"),
118-
Filter::equal('type', KConfig::DEFAULT_NOTIFICATIONS_TYPE)
119-
))
120-
->first();
121-
122-
if ($source === null) {
123-
throw new LogicException($this->translate('Source not created'));
124-
}
125-
126-
$values[KConfig::NOTIFICATIONS_USERNAME] = "source-$source->id";
127131
} catch (Throwable $e) {
128132
Logger::error($e);
129133
Logger::error($e->getTraceAsString());
@@ -132,6 +136,8 @@ function (NotificationsConfigForm $form) use ($sourceForm) {
132136
}
133137
}
134138

139+
$values[KConfig::NOTIFICATIONS_USERNAME] = $clusterUuid;
140+
135141
try {
136142
Database::connection()->transaction(function (Connection $db) use ($values, $clusterUuid) {
137143
$key = $db->quoteIdentifier('key');
@@ -184,7 +190,7 @@ public function prometheusAction()
184190
->getNamespace('kubernetes')
185191
->get('cluster_uuid')
186192
])
187-
->on(PrometheusConfigForm::ON_SUCCESS, function (PrometheusConfigForm $form) {
193+
->on(PrometheusConfigForm::ON_SUBMIT, function (PrometheusConfigForm $form) {
188194
if ($form->isLocked()) {
189195
$form->addMessage($this->translate('Prometheus configuration is locked.'));
190196

@@ -249,6 +255,7 @@ protected function createOrUpdateSource(SourceForm $sourceForm, string $clusterU
249255
$password = sha1(openssl_random_pseudo_bytes(16));
250256

251257
$formData = [
258+
'listener_username' => $clusterUuid,
252259
'listener_password' => $password,
253260
'listener_password_dupe' => $password,
254261
'name' => KConfig::DEFAULT_NOTIFICATIONS_NAME . " ($clusterUuid)",
@@ -272,21 +279,16 @@ protected function createOrUpdateSource(SourceForm $sourceForm, string $clusterU
272279
$sourceForm->populate($formData);
273280

274281
if ($source !== null) {
275-
$sourceForm->on(SourceForm::ON_SUCCESS, function (SourceForm $form) {
282+
$sourceForm->on(SourceForm::ON_SUBMIT, function (SourceForm $form) {
276283
$form->editSource();
277284
});
278285
} else {
279-
$sourceForm->on(SourceForm::ON_SUCCESS, function (SourceForm $form) {
286+
$sourceForm->on(SourceForm::ON_SUBMIT, function (SourceForm $form) {
280287
$form->addSource();
281288
});
282289
}
283290

284-
$sourceForm->ensureAssembled();
285-
$csrf = $sourceForm->getElement('CSRFToken');
286-
if (preg_match('/ value="([^"]+)/', $csrf->getAttributes()->render(), $matches)) {
287-
$csrf->setValue($matches[1]);
288-
}
289-
291+
$sourceForm->disableCsrfCounterMeasure();
290292
$sourceForm->handleRequest(ServerRequest::fromGlobals());
291293

292294
return $password;

application/forms/NotificationsConfigForm.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ protected function assemble(): void
142142
$kconfig = $this->getKConfig($clusterUuid);
143143

144144
$this->addElement('text', static::transformKeyForForm(KConfig::NOTIFICATIONS_URL), [
145+
'required' => true,
145146
'label' => $this->translate('Icinga Notifications URL'),
146147
'disabled' => $kconfig[KConfig::NOTIFICATIONS_URL]->locked ?? false,
147148
'value' => $kconfig[KConfig::NOTIFICATIONS_URL]->value ?? null,

library/Kubernetes/ProvidedHook/Notifications/ObjectsRenderer.php

Lines changed: 55 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
namespace Icinga\Module\Kubernetes\ProvidedHook\Notifications;
66

77
use Generator;
8+
use Icinga\Module\Kubernetes\Common\Database;
89
use Icinga\Module\Kubernetes\Common\Factory;
10+
use Icinga\Module\Kubernetes\Model\Cluster;
911
use Icinga\Module\Kubernetes\Web\ItemList\ResourceList;
1012
use Icinga\Module\Kubernetes\Web\Widget\KIcon;
1113
use Icinga\Module\Notifications\Hook\ObjectsRendererHook;
1214
use ipl\Html\Attributes;
1315
use ipl\Html\FormattedString;
14-
use ipl\Html\Html;
16+
use ipl\Html\HtmlDocument;
1517
use ipl\Html\HtmlElement;
1618
use ipl\Html\Text;
1719
use ipl\Html\ValidHtml;
@@ -45,10 +47,15 @@ public function createObjectLink(array $objectIdTag): ?ValidHtml
4547
return null;
4648
}
4749

48-
return (new ResourceList(
50+
$html = new ResourceList(
4951
Factory::fetchResource($objectIdTag['resource'])
5052
->filter(Filter::equal('uuid', Uuid::fromString($objectIdTag['uuid'])->getBytes()))
51-
));
53+
);
54+
// TODO(el): Icinga Notifications Web now forcefully adds the target, which results in having it twice,
55+
// ultimately leading to JS errors.
56+
$html->removeAttribute('data-base-target');
57+
58+
return $html;
5259
}
5360

5461
/**
@@ -61,147 +68,71 @@ public function createObjectLink(array $objectIdTag): ?ValidHtml
6168
*/
6269
protected function yieldObjectsResults(array $objectIdTags, bool $asHtml): Generator
6370
{
71+
$clusterNames = [];
72+
6473
foreach ($objectIdTags as $idTags) {
6574
if (! isset($idTags['resource']) || ! isset($idTags['name'])) {
6675
continue;
6776
}
6877

69-
switch ($idTags['resource']) {
70-
case 'pod':
71-
if (! $asHtml) {
72-
yield $idTags => sprintf(
73-
$this->translate('%s - %s', '<namespace> - <name>'),
74-
$idTags['namespace'],
75-
$idTags['name']
76-
);
77-
} else {
78-
yield $idTags => Html::sprintf(
79-
$this->translate('%s', '<pod>'),
80-
[
81-
new HtmlElement(
82-
'span',
83-
new Attributes(['class' => 'namespace-badge']),
84-
new KIcon('namespace'),
85-
new Text($idTags['namespace'])
86-
),
87-
new HtmlElement(
88-
'span',
89-
new Attributes(['class' => 'subject']),
90-
new KIcon('pod'),
91-
new Text($idTags['name'])
92-
)
93-
]
94-
);
95-
}
78+
$clusterName = 'default';
79+
if (isset($idTags['cluster_uuid'])) {
80+
$clusterNames[$idTags['cluster_uuid']] ??= Cluster::on(Database::connection())
81+
->columns('name')
82+
->filter(Filter::equal('uuid', Uuid::fromString($idTags['cluster_uuid'])->getBytes()))
83+
->first()
84+
?->name ?? $idTags['cluster_uuid'];
9685

97-
break;
98-
case 'deployment':
99-
if (! $asHtml) {
100-
yield $idTags => sprintf($this->translate('%s', '<deployment>'), $idTags['name']);
101-
} else {
102-
yield $idTags => Html::sprintf(
103-
$this->translate('%s', '<deployment>'),
104-
[
105-
new HtmlElement(
106-
'span',
107-
new Attributes(['class' => 'namespace-badge']),
108-
new KIcon('namespace'),
109-
new Text($idTags['namespace'])
110-
),
111-
new HtmlElement(
112-
'span',
113-
new Attributes(['class' => 'subject']),
114-
new KIcon('deployment'),
115-
new Text($idTags['name'])
116-
)
117-
]
118-
);
119-
}
86+
$clusterName = $clusterNames[$idTags['cluster_uuid']] ?? $idTags['cluster_uuid'];
87+
}
12088

121-
break;
89+
switch ($idTags['resource']) {
12290
case 'node':
12391
if (! $asHtml) {
124-
yield $idTags => sprintf($this->translate('%s', '<node>'), $idTags['name']);
92+
yield $idTags => sprintf('%s@%s', $idTags['name'], $clusterName);
12593
} else {
126-
yield $idTags => Html::sprintf(
127-
$this->translate('%s', '<node>'),
128-
new HtmlElement(
94+
yield $idTags => (new HtmlDocument())
95+
->addHtml(new HtmlElement(
12996
'span',
13097
new Attributes(['class' => 'subject']),
13198
new Icon('share-nodes'),
13299
new Text($idTags['name'])
133-
)
134-
);
135-
}
136-
break;
137-
case 'daemon_set':
138-
if (! $asHtml) {
139-
yield $idTags => sprintf($this->translate('%s', '<daemon_set>'), $idTags['name']);
140-
} else {
141-
yield $idTags => Html::sprintf(
142-
$this->translate('%s', '<daemon_set>'),
143-
[
144-
new HtmlElement(
145-
'span',
146-
new Attributes(['class' => 'namespace-badge']),
147-
new KIcon('namespace'),
148-
new Text($idTags['namespace'])
149-
),
150-
new HtmlElement(
151-
'span',
152-
new Attributes(['class' => 'subject']),
153-
new KIcon('daemonset'),
154-
new Text($idTags['name'])
155-
)
156-
]
157-
);
100+
))
101+
->addHtml(new HtmlElement(
102+
'span',
103+
new Attributes(['class' => 'cluster-name']),
104+
new Icon('circle-nodes'),
105+
new Text($clusterName)
106+
));
158107
}
108+
159109
break;
160-
case 'replica_set':
110+
default:
161111
if (! $asHtml) {
162-
yield $idTags => sprintf($this->translate('%s', '<replica_set>'), $idTags['name']);
112+
yield $idTags => sprintf('%s/%s@%s', $idTags['namespace'], $idTags['name'], $clusterName);
163113
} else {
164-
yield $idTags => Html::sprintf(
165-
$this->translate('%s', '<replica_set>'),
166-
[
167-
new HtmlElement(
168-
'span',
169-
new Attributes(['class' => 'namespace-badge']),
170-
new KIcon('namespace'),
171-
new Text($idTags['namespace'])
172-
),
173-
new HtmlElement(
174-
'span',
175-
new Attributes(['class' => 'subject']),
176-
new KIcon('replicaset'),
177-
new Text($idTags['name'])
178-
)
179-
]
180-
);
114+
yield $idTags => (new HtmlDocument())
115+
->addHtml(new HtmlElement(
116+
'span',
117+
new Attributes(['class' => 'namespace-badge']),
118+
new KIcon('namespace'),
119+
new Text($idTags['namespace'])
120+
))
121+
->addHtml(new HtmlElement(
122+
'span',
123+
new Attributes(['class' => 'subject']),
124+
Factory::createIcon($idTags['resource']),
125+
new Text($idTags['name'])
126+
))
127+
->addHtml(new HtmlElement(
128+
'span',
129+
new Attributes(['class' => 'cluster-name']),
130+
new Icon('circle-nodes'),
131+
new Text($clusterName)
132+
));
181133
}
134+
182135
break;
183-
case 'stateful_set':
184-
if (! $asHtml) {
185-
yield $idTags => sprintf($this->translate('%s', '<stateful_set>'), $idTags['name']);
186-
} else {
187-
yield $idTags => Html::sprintf(
188-
$this->translate('%s is %s', '<stateful_set> is <icinga_state>'),
189-
[
190-
new HtmlElement(
191-
'span',
192-
new Attributes(['class' => 'namespace-badge']),
193-
new KIcon('namespace'),
194-
new Text($idTags['namespace'])
195-
),
196-
new HtmlElement(
197-
'span',
198-
new Attributes(['class' => 'subject']),
199-
new KIcon('statefulset'),
200-
new Text($idTags['name'])
201-
)
202-
]
203-
);
204-
}
205136
}
206137
}
207138
}

0 commit comments

Comments
 (0)