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

api/v2: Check if cluster peer is nil -> release-0.16 #1726

Merged
merged 1 commit into from
Jan 31, 2019
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## Next release

* [BUGFIX] Do not populate cluster info if clustering is disabled in API v2 (#1726)

## 0.16.0 / 2019-01-17

This release introduces a new API v2, fully generated via the OpenAPI project
Expand Down
31 changes: 23 additions & 8 deletions api/v2/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,12 @@ func (api *API) getStatusHandler(params general_ops.GetStatusParams) middleware.
api.mtx.RLock()
defer api.mtx.RUnlock()

name := api.peer.Name()
status := api.peer.Status()
original := api.alertmanagerConfig.String()
uptime := strfmt.DateTime(api.uptime)

name := ""
status := open_api_models.ClusterStatusStatusDisabled

resp := open_api_models.AlertmanagerStatus{
Uptime: &uptime,
VersionInfo: &open_api_models.VersionInfo{
Expand All @@ -153,12 +155,25 @@ func (api *API) getStatusHandler(params general_ops.GetStatusParams) middleware.
},
}

for _, n := range api.peer.Peers() {
address := n.Address()
resp.Cluster.Peers = append(resp.Cluster.Peers, &open_api_models.PeerStatus{
Name: &n.Name,
Address: &address,
})
// If alertmanager cluster feature is disabled, then api.peers == nil.
if api.peer != nil {
name := api.peer.Name()
status := api.peer.Status()

peers := []*open_api_models.PeerStatus{}
for _, n := range api.peer.Peers() {
address := n.Address()
peers = append(peers, &open_api_models.PeerStatus{
Name: &n.Name,
Address: &address,
})
}

resp.Cluster = &open_api_models.ClusterStatus{
mxinden marked this conversation as resolved.
Show resolved Hide resolved
Name: &name,
Status: &status,
Peers: peers,
}
}

return general_ops.NewGetStatusOK().WithPayload(&resp)
Expand Down
42 changes: 42 additions & 0 deletions api/v2/api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2019 Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package v2

import (
"testing"
"time"

general_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/general"
"github.com/prometheus/alertmanager/config"
)

// If api.peers == nil, Alertmanager cluster feature is disabled. Make sure to
// not try to access properties of peer, hence triggering a nil pointer
// dereference.
func TestGetStatusHandlerWithNilPeer(t *testing.T) {
api := API{
uptime: time.Now(),
peer: nil,
alertmanagerConfig: &config.Config{},
}

// Test ensures this method call does not panic.
status := api.getStatusHandler(general_ops.GetStatusParams{}).(*general_ops.GetStatusOK)

c := status.Payload.Cluster

if c == nil || c.Status == nil || c.Name == nil || c.Peers == nil {
t.Fatal("expected cluster {status,name,peers} not to be nil, violating the openapi specification")
}
}
39 changes: 39 additions & 0 deletions api/v2/models/cluster_status.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions api/v2/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ definitions:
type: string
status:
type: string
enum: ["ready", "settling", "disabled"]
peers:
type: array
minimum: 0
Expand Down
14 changes: 12 additions & 2 deletions api/v2/restapi/embedded_spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions asset/assets_vfsdata.go

Large diffs are not rendered by default.

39 changes: 39 additions & 0 deletions test/with_api_v2/api_v2_client/models/cluster_status.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 43 additions & 4 deletions ui/app/src/Data/ClusterStatus.elm
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
-}


module Data.ClusterStatus exposing (ClusterStatus, decoder, encoder)
module Data.ClusterStatus exposing (ClusterStatus, Status(..), decoder, encoder)

import Data.PeerStatus as PeerStatus exposing (PeerStatus)
import Dict exposing (Dict)
Expand All @@ -21,23 +21,62 @@ import Json.Encode as Encode

type alias ClusterStatus =
{ name : String
, status : String
, status : Status
, peers : List PeerStatus
}


type Status
= Ready
| Settling
| Disabled


decoder : Decoder ClusterStatus
decoder =
Decode.succeed ClusterStatus
|> required "name" Decode.string
|> required "status" Decode.string
|> required "status" statusDecoder
|> required "peers" (Decode.list PeerStatus.decoder)


encoder : ClusterStatus -> Encode.Value
encoder model =
Encode.object
[ ( "name", Encode.string model.name )
, ( "status", Encode.string model.status )
, ( "status", statusEncoder model.status )
, ( "peers", Encode.list PeerStatus.encoder model.peers )
]


statusDecoder : Decoder Status
statusDecoder =
Decode.string
|> Decode.andThen
(\str ->
case str of
"ready" ->
Decode.succeed Ready

"settling" ->
Decode.succeed Settling

"disabled" ->
Decode.succeed Disabled

other ->
Decode.fail <| "Unknown type: " ++ other
)


statusEncoder : Status -> Encode.Value
statusEncoder model =
case model of
Ready ->
Encode.string "ready"

Settling ->
Encode.string "settling"

Disabled ->
Encode.string "disabled"
16 changes: 15 additions & 1 deletion ui/app/src/Status/Api.elm
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module Status.Api exposing (getStatus)
module Status.Api exposing (clusterStatusToString, getStatus)

import Data.AlertmanagerStatus exposing (AlertmanagerStatus)
import Data.ClusterStatus exposing (Status(..))
import Json.Decode exposing (Decoder, at, bool, field, int, list, map2, maybe, string)
import Status.Types exposing (ClusterPeer, ClusterStatus, StatusResponse, VersionInfo)
import Utils.Api exposing (get, send)
Expand All @@ -19,6 +20,19 @@ getStatus apiUrl msg =
Cmd.map msg <| send request


clusterStatusToString : Status -> String
clusterStatusToString status =
case status of
Ready ->
"ready"

Settling ->
"settling"

Disabled ->
"disabled"


decodeStatusResponse : Decoder StatusResponse
decodeStatusResponse =
field "data" decodeData
Expand Down
Loading