Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ui): show cluster name on silences instead of each alertmanager #1827

Merged
merged 6 commits into from
Jun 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions cmd/karma/views.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,16 @@ func alerts(c *gin.Context) {

agCopy.Alerts = append(agCopy.Alerts, alert)

if len(upstreams.Clusters) > 1 {
clusters := map[string]bool{}
for _, am := range alert.Alertmanager {
clusters[am.Cluster] = true
}
for cluster := range clusters {
countLabel(counters, "@cluster", cluster)
}
}

countLabel(counters, "@state", alert.State)

countLabel(counters, "@receiver", alert.Receiver)
Expand Down Expand Up @@ -569,9 +579,9 @@ func silences(c *gin.Context) {
if searchTerm != "" {
upstreams := getUpstreams()
for _, u := range upstreams.Instances {
if strings.ToLower(u.Name) == searchTerm {
if strings.ToLower(u.Name) == searchTerm || strings.ToLower(u.Cluster) == searchTerm {
if !slices.StringInSlice(clusters, u.Cluster) {
clusters = append(clusters, u.Cluster)
clusters = append(clusters, strings.ToLower(u.Cluster))
}
}
}
Expand All @@ -585,7 +595,9 @@ func silences(c *gin.Context) {
isMatch := false
if strings.ToLower(silence.Silence.ID) == searchTerm {
isMatch = true
} else if slices.StringInSlice(clusters, silence.Cluster) {
} else if fmt.Sprintf("@cluster=%s", strings.ToLower(silence.Cluster)) == searchTerm {
isMatch = true
} else if slices.StringInSlice(clusters, strings.ToLower(silence.Cluster)) {
isMatch = true
} else if strings.Contains(strings.ToLower(silence.Silence.Comment), searchTerm) {
isMatch = true
Expand Down Expand Up @@ -633,9 +645,11 @@ func silences(c *gin.Context) {
}
for _, alertGroup := range alertmanager.DedupAlerts() {
for _, alert := range alertGroup.Alerts {
for _, sID := range alert.SilencedBy {
if _, ok := silenceCounters[sID]; ok {
silenceCounters[sID]++
for _, am := range alert.Alertmanager {
for _, sID := range am.SilencedBy {
if _, ok := silenceCounters[sID]; ok {
silenceCounters[sID]++
}
}
}
}
Expand Down
26 changes: 25 additions & 1 deletion cmd/karma/views_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,30 @@ func TestSilences(t *testing.T) {
showExpired: "1",
results: []string{},
},
{
searchTerm: "@cluster=foo",
sortReverse: "0",
showExpired: "0",
results: []string{},
},
{
searchTerm: "@cluster=default",
sortReverse: "0",
showExpired: "0",
results: []string{silenceHostDown, silenceInstance, silenceServer7},
},
{
searchTerm: "@cluster=default",
sortReverse: "0",
showExpired: "1",
results: []string{silenceHostDown, silenceInstance, silenceServer7},
},
{
searchTerm: "@cluster=default",
sortReverse: "1",
showExpired: "1",
results: []string{silenceHostDown, silenceInstance, silenceServer7},
},
}

mockConfig()
Expand Down Expand Up @@ -753,7 +777,7 @@ func TestSilences(t *testing.T) {
}
sort.Strings(results) // can't rely on API order since it's sorted based on timestamps, resort
if diff := cmp.Diff(testCase.results, results); diff != "" {
t.Errorf("Wrong silences returned (-want +got):\n%s", diff)
t.Errorf("Wrong silences returned for '%s' (-want +got):\n%s", uri, diff)
}
}
}
Expand Down
18 changes: 5 additions & 13 deletions ui/src/Components/ManagedSilence/SilenceComment.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@ const SilenceComment = ({
silence.comment
);

const alertmanagers = alertStore.data.upstreams.instances.filter(
(u) => u.cluster === cluster
);

return (
<React.Fragment>
<div className="d-flex flex-row">
Expand All @@ -65,15 +61,11 @@ const SilenceComment = ({
&mdash; {silence.createdBy}
</span>
{collapsed &&
Object.keys(alertStore.data.upstreams.clusters).length > 1 &&
alertmanagers.map((alertmanager) => (
<span
key={alertmanager.name}
className="badge badge-secondary mx-1 align-text-bottom p-1"
>
{alertmanager.name}
</span>
))}
Object.keys(alertStore.data.upstreams.clusters).length > 1 ? (
<span className="badge badge-secondary mx-1 align-text-bottom p-1">
{cluster}
</span>
) : null}
{collapsed ? <SilenceProgress silence={silence} /> : null}
</div>
</div>
Expand Down
57 changes: 28 additions & 29 deletions ui/src/Components/ManagedSilence/SilenceComment.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ afterEach(() => {

const CollapseMock = jest.fn();

const MountedSilenceComment = (collapsed) => {
const MountedSilenceComment = (collapsed, cluster) => {
return mount(
<SilenceComment
alertStore={alertStore}
alertCount={123}
cluster="default"
cluster={cluster || "default"}
silence={silence}
collapsed={collapsed}
collapseToggle={CollapseMock}
Expand All @@ -37,43 +37,43 @@ const MountedSilenceComment = (collapsed) => {

const MockMultipleClusters = () => {
alertStore.data.upstreams = {
clusters: { default: ["default", "fallback"], second: ["second"] },
clusters: { ha: ["ha1", "ha2"], single: ["single"] },
instances: [
{
name: "default",
uri: "http://am1.example.com",
publicURI: "http://am1.example.com",
name: "ha1",
uri: "http://ha1.example.com",
publicURI: "http://ha1.example.com",
readonly: false,
headers: {},
corsCredentials: "include",
error: "",
version: "0.17.0",
cluster: "default",
clusterMembers: ["default", "fallback"],
cluster: "ha",
clusterMembers: ["ha1", "ha2"],
},
{
name: "fallback",
uri: "http://am2.example.com",
publicURI: "http://am2.example.com",
name: "ha2",
uri: "http://ha2.example.com",
publicURI: "http://ha2.example.com",
readonly: false,
headers: {},
corsCredentials: "include",
error: "",
version: "0.17.0",
cluster: "default",
clusterMembers: ["default", "fallback"],
cluster: "ha",
clusterMembers: ["ha1", "ha2"],
},
{
name: "second",
uri: "http://am3.example.com",
publicURI: "http://am3.example.com",
name: "single",
uri: "http://single.example.com",
publicURI: "http://single.example.com",
readonly: false,
headers: {},
corsCredentials: "include",
error: "",
version: "0.17.0",
cluster: "second",
clusterMembers: ["second"],
cluster: "single",
clusterMembers: ["single"],
},
],
};
Expand All @@ -92,13 +92,13 @@ describe("<SilenceComment />", () => {

it("Matches snapshot when collapsed and multiple clusters are present", () => {
MockMultipleClusters();
const tree = MountedSilenceComment(true);
const tree = MountedSilenceComment(true, "ha");
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
});

it("Matches snapshot when collapsed and multiple clusters are present", () => {
MockMultipleClusters();
const tree = MountedSilenceComment(false);
const tree = MountedSilenceComment(false, "ha");
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
});

Expand All @@ -123,30 +123,29 @@ describe("<SilenceComment />", () => {
expect(CollapseMock).toHaveBeenCalled();
});

it("Doesn't render alertmanager badges when collapsed and only a single cluster is present", () => {
it("Doesn't render cluster badges when collapsed and only a single cluster is present", () => {
const tree = MountedSilenceComment(true);
const ams = tree.find("span.badge.badge-secondary");
expect(ams).toHaveLength(0);
});

it("Doesn't render alertmanager badges when expanded and only a single cluster is present", () => {
it("Doesn't render cluster badges when expanded and only a single cluster is present", () => {
const tree = MountedSilenceComment(false);
const ams = tree.find("span.badge.badge-secondary");
expect(ams).toHaveLength(0);
});

it("Renders alertmanager badges when collapsed and multiple clusters are present", () => {
it("Renders cluster badge when collapsed and multiple clusters are present", () => {
MockMultipleClusters();
const tree = MountedSilenceComment(true);
const tree = MountedSilenceComment(true, "single");
const ams = tree.find("span.badge.badge-secondary");
expect(ams).toHaveLength(2);
expect(toDiffableHtml(ams.at(0).html())).toMatch(/default/);
expect(toDiffableHtml(ams.at(1).html())).toMatch(/fallback/);
expect(ams).toHaveLength(1);
expect(toDiffableHtml(ams.at(0).html())).toMatch(/single/);
});

it("Doesn't render alertmanager badges when expanded and multiple clusters are present", () => {
it("Doesn't render cluster badge when expanded and multiple clusters are present", () => {
MockMultipleClusters();
const tree = MountedSilenceComment(false);
const tree = MountedSilenceComment(false, "single");
const ams = tree.find("span.badge.badge-secondary");
expect(ams).toHaveLength(0);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,7 @@ exports[`<SilenceComment /> Matches snapshot when collapsed and multiple cluster
— me@example.com
</span>
<span class=\\"badge badge-secondary mx-1 align-text-bottom p-1\\">
default
</span>
<span class=\\"badge badge-secondary mx-1 align-text-bottom p-1\\">
fallback
ha
</span>
<span class=\\"badge badge-danger align-text-bottom p-1\\">
Expired
Expand Down
22 changes: 14 additions & 8 deletions ui/src/__mocks__/Stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ const MockGrid = (alertStore) => {
const silence = MockSilence();
silence.startsAt = "2018-08-14T12:00:00Z";
silence.endsAt = "2018-08-14T18:00:00Z";
alertStore.data.silences = { am: {} };
alertStore.data.silences["am"][silence.id] = silence;
alertStore.data.silences = { prod: {} };
alertStore.data.silences["prod"][silence.id] = silence;

alertStore.data.colors = {
group: {
Expand Down Expand Up @@ -190,8 +190,8 @@ const MockGrid = (alertStore) => {
if (group.alerts[j].state === "suppressed") {
group.alerts[j].alertmanager = [
{
name: "am1",
cluster: "am",
name: "prod1",
cluster: "prod",
state: "suppressed",
startsAt: "2018-08-14T17:36:40.017867056Z",
source: "localhost/prometheus",
Expand Down Expand Up @@ -229,20 +229,26 @@ const MockGrid = (alertStore) => {
alertStore.data.upstreams = {
counters: { total: 3, healthy: 1, failed: 2 },
instances: [
{ name: "am1", uri: "http://localhost:9093", error: "" },
{
name: "am2",
name: "prod1",
cluster: "prod",
uri: "http://localhost:9093",
error: "",
},
{
name: "prod2",
cluster: "prod",
uri: "http://localhost:9094",
error: "Failed to connect to http://localhost:9094",
},
{
name: "failed",
name: "dev",
uri: "https://am.example.com",
error:
"Failed to connect to https://am.example.com veryLongStringToTestTextWrappingveryLongStringToTestTextWrappingveryLongStringToTestTextWrappingveryLongStringToTestTextWrappingveryLongStringToTestTextWrappingveryLongStringToTestTextWrapping",
},
],
clusters: { am: ["am1", "am2"], failed: ["failed"] },
clusters: { prod: ["prod1", "prod2"], dev: ["dev"] },
};
alertStore.data.grids = [
{
Expand Down