Skip to content

Commit 174b449

Browse files
authored
Merge pull request #9 from arangodb/pod-monitoring
Pod monitoring
2 parents 07497c7 + a682223 commit 174b449

File tree

13 files changed

+665
-31
lines changed

13 files changed

+665
-31
lines changed

main.go

+1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ func main() {
9595

9696
// Run the operator
9797
func cmdMainRun(cmd *cobra.Command, args []string) {
98+
goflag.CommandLine.Parse([]string{"-logtostderr"})
9899
var err error
99100
logService, err = logging.NewService(logLevel)
100101
if err != nil {
+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2018 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
// Author Ewout Prangsma
21+
//
22+
23+
package v1alpha
24+
25+
import (
26+
"k8s.io/api/core/v1"
27+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28+
)
29+
30+
// ConditionType is a strongly typed condition name
31+
type ConditionType string
32+
33+
const (
34+
// ConditionTypeReady indicates that the member or entire deployment is ready and running normally.
35+
ConditionTypeReady ConditionType = "Ready"
36+
)
37+
38+
// Condition represents one current condition of a deployment or deployment member.
39+
// A condition might not show up if it is not happening.
40+
// For example, if a cluster is not upgrading, the Upgrading condition would not show up.
41+
type Condition struct {
42+
// Type of condition.
43+
Type ConditionType `json:"type"`
44+
// Status of the condition, one of True, False, Unknown.
45+
Status v1.ConditionStatus `json:"status"`
46+
// The last time this condition was updated.
47+
LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"`
48+
// Last time the condition transitioned from one status to another.
49+
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
50+
// The reason for the condition's last transition.
51+
Reason string `json:"reason,omitempty"`
52+
// A human readable message indicating details about the transition.
53+
Message string `json:"message,omitempty"`
54+
}
55+
56+
// ConditionList is a list of conditions.
57+
// Each type is allowed only once.
58+
type ConditionList []Condition
59+
60+
// IsTrue return true when a condition with given type exists and its status is `True`.
61+
func (list ConditionList) IsTrue(conditionType ConditionType) bool {
62+
c, found := list.Get(conditionType)
63+
return found && c.Status == v1.ConditionTrue
64+
}
65+
66+
// Get a condition by type.
67+
// Returns true if found, false if not found.
68+
func (list ConditionList) Get(conditionType ConditionType) (Condition, bool) {
69+
for _, x := range list {
70+
if x.Type == conditionType {
71+
return x, true
72+
}
73+
}
74+
// Not found
75+
return Condition{}, false
76+
}
77+
78+
// Update the condition, replacing an old condition with same type (if any)
79+
// Returns true when changes were made, false otherwise.
80+
func (list *ConditionList) Update(conditionType ConditionType, status bool, reason, message string) bool {
81+
src := *list
82+
statusX := v1.ConditionFalse
83+
if status {
84+
statusX = v1.ConditionTrue
85+
}
86+
for i, x := range src {
87+
if x.Type == conditionType {
88+
if x.Status != statusX {
89+
// Transition to another status
90+
src[i].Status = statusX
91+
now := metav1.Now()
92+
src[i].LastTransitionTime = now
93+
src[i].LastUpdateTime = now
94+
src[i].Reason = reason
95+
src[i].Message = message
96+
} else if x.Reason != reason || x.Message != message {
97+
src[i].LastUpdateTime = metav1.Now()
98+
src[i].Reason = reason
99+
src[i].Message = message
100+
} else {
101+
return false
102+
}
103+
return true
104+
}
105+
}
106+
// Not found
107+
now := metav1.Now()
108+
*list = append(src, Condition{
109+
Type: conditionType,
110+
LastUpdateTime: now,
111+
LastTransitionTime: now,
112+
Status: statusX,
113+
Reason: reason,
114+
Message: message,
115+
})
116+
return true
117+
}
118+
119+
// Remove the condition with given type.
120+
// Returns true if removed, or false if not found.
121+
func (list *ConditionList) Remove(conditionType ConditionType) bool {
122+
src := *list
123+
for i, x := range src {
124+
if x.Type == conditionType {
125+
*list = append(src[:i], src[i+1:]...)
126+
return true
127+
}
128+
}
129+
// Not found
130+
return false
131+
}

pkg/apis/arangodb/v1alpha/deployment_status.go

+112-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@
2222

2323
package v1alpha
2424

25-
import "github.com/pkg/errors"
25+
import (
26+
"fmt"
27+
28+
"github.com/pkg/errors"
29+
)
2630

2731
// DeploymentState is a strongly typed state of a deployment
2832
type DeploymentState string
@@ -64,6 +68,9 @@ type DeploymentStatus struct {
6468

6569
// Members holds the status for all members in all server groups
6670
Members DeploymentStatusMembers `json:"members"`
71+
72+
// Conditions specific to the entire deployment
73+
Conditions ConditionList `json:"conditions,omitempty"`
6774
}
6875

6976
// DeploymentStatusMembers holds the member status of all server groups
@@ -86,6 +93,95 @@ func (ds DeploymentStatusMembers) ContainsID(id string) bool {
8693
ds.SyncWorkers.ContainsID(id)
8794
}
8895

96+
// ForeachServerGroup calls the given callback for all server groups.
97+
// If the callback returns an error, this error is returned and the callback is
98+
// not called for the remaining groups.
99+
func (ds DeploymentStatusMembers) ForeachServerGroup(cb func(group ServerGroup, list *MemberStatusList) error) error {
100+
if err := cb(ServerGroupSingle, &ds.Single); err != nil {
101+
return maskAny(err)
102+
}
103+
if err := cb(ServerGroupAgents, &ds.Agents); err != nil {
104+
return maskAny(err)
105+
}
106+
if err := cb(ServerGroupDBServers, &ds.DBServers); err != nil {
107+
return maskAny(err)
108+
}
109+
if err := cb(ServerGroupCoordinators, &ds.Coordinators); err != nil {
110+
return maskAny(err)
111+
}
112+
if err := cb(ServerGroupSyncMasters, &ds.SyncMasters); err != nil {
113+
return maskAny(err)
114+
}
115+
if err := cb(ServerGroupSyncWorkers, &ds.SyncWorkers); err != nil {
116+
return maskAny(err)
117+
}
118+
return nil
119+
}
120+
121+
// MemberStatusByPodName returns a reference to the element in the given set of lists that has the given pod name.
122+
// If no such element exists, nil is returned.
123+
func (ds DeploymentStatusMembers) MemberStatusByPodName(podName string) (MemberStatus, ServerGroup, bool) {
124+
if result, found := ds.Single.ElementByPodName(podName); found {
125+
return result, ServerGroupSingle, true
126+
}
127+
if result, found := ds.Agents.ElementByPodName(podName); found {
128+
return result, ServerGroupAgents, true
129+
}
130+
if result, found := ds.DBServers.ElementByPodName(podName); found {
131+
return result, ServerGroupDBServers, true
132+
}
133+
if result, found := ds.Coordinators.ElementByPodName(podName); found {
134+
return result, ServerGroupCoordinators, true
135+
}
136+
if result, found := ds.SyncMasters.ElementByPodName(podName); found {
137+
return result, ServerGroupSyncMasters, true
138+
}
139+
if result, found := ds.SyncWorkers.ElementByPodName(podName); found {
140+
return result, ServerGroupSyncWorkers, true
141+
}
142+
return MemberStatus{}, 0, false
143+
}
144+
145+
// UpdateMemberStatus updates the given status in the given group.
146+
func (ds *DeploymentStatusMembers) UpdateMemberStatus(status MemberStatus, group ServerGroup) error {
147+
var err error
148+
switch group {
149+
case ServerGroupSingle:
150+
err = ds.Single.Update(status)
151+
case ServerGroupAgents:
152+
err = ds.Agents.Update(status)
153+
case ServerGroupDBServers:
154+
err = ds.DBServers.Update(status)
155+
case ServerGroupCoordinators:
156+
err = ds.Coordinators.Update(status)
157+
case ServerGroupSyncMasters:
158+
err = ds.SyncMasters.Update(status)
159+
case ServerGroupSyncWorkers:
160+
err = ds.SyncWorkers.Update(status)
161+
default:
162+
return maskAny(errors.Wrapf(NotFoundError, "ServerGroup %d is not known", group))
163+
}
164+
if err != nil {
165+
return maskAny(err)
166+
}
167+
return nil
168+
}
169+
170+
// AllMembersReady returns true when all members are in the Ready state.
171+
func (ds DeploymentStatusMembers) AllMembersReady() bool {
172+
if err := ds.ForeachServerGroup(func(group ServerGroup, list *MemberStatusList) error {
173+
for _, x := range *list {
174+
if !x.Conditions.IsTrue(ConditionTypeReady) {
175+
return fmt.Errorf("not ready")
176+
}
177+
}
178+
return nil
179+
}); err != nil {
180+
return false
181+
}
182+
return true
183+
}
184+
89185
// MemberStatusList is a list of MemberStatus entries
90186
type MemberStatusList []MemberStatus
91187

@@ -99,6 +195,17 @@ func (l MemberStatusList) ContainsID(id string) bool {
99195
return false
100196
}
101197

198+
// ElementByPodName returns the element in the given list that has the given pod name and true.
199+
// If no such element exists, an empty element and false is returned.
200+
func (l MemberStatusList) ElementByPodName(podName string) (MemberStatus, bool) {
201+
for i, x := range l {
202+
if x.PodName == podName {
203+
return l[i], true
204+
}
205+
}
206+
return MemberStatus{}, false
207+
}
208+
102209
// Add a member to the list.
103210
// Returns an AlreadyExistsError if the ID of the given member already exists.
104211
func (l *MemberStatusList) Add(m MemberStatus) error {
@@ -143,10 +250,8 @@ type MemberState string
143250
const (
144251
// MemberStateNone indicates that the state is not set yet
145252
MemberStateNone MemberState = ""
146-
// MemberStateCreating indicates that the member is in the process of being created
147-
MemberStateCreating MemberState = "Creating"
148-
// MemberStateReady indicates that the member is running and reachable
149-
MemberStateReady MemberState = "Ready"
253+
// MemberStateCreated indicates that all resources needed for the member have been created
254+
MemberStateCreated MemberState = "Created"
150255
// MemberStateCleanOut indicates that a dbserver is in the process of being cleaned out
151256
MemberStateCleanOut MemberState = "CleanOut"
152257
// MemberStateShuttingDown indicates that a member is shutting down
@@ -164,4 +269,6 @@ type MemberStatus struct {
164269
PersistentVolumeClaimName string `json:"persistentVolumeClaimName,omitempty"`
165270
// PodName holds the name of the Pod that currently runs this member
166271
PodName string `json:"podName,omitempty"`
272+
// Conditions specific to this member
273+
Conditions ConditionList `json:"conditions,omitempty"`
167274
}

0 commit comments

Comments
 (0)