@@ -22,44 +22,80 @@ package cmd
2222
2323import (
2424 "crypto/tls"
25+ "encoding/json"
2526 "fmt"
2627 "io/ioutil"
2728 "net/http"
2829 "os"
2930 "path"
31+ "strconv"
3032
3133 "github.com/pkg/errors"
3234 "github.com/rs/zerolog/log"
3335 "github.com/spf13/cobra"
3436
37+ "github.com/arangodb/go-driver"
3538 "github.com/arangodb/go-driver/jwt"
3639
40+ api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
3741 "github.com/arangodb/kube-arangodb/pkg/apis/shared"
42+ "github.com/arangodb/kube-arangodb/pkg/deployment/client"
43+ "github.com/arangodb/kube-arangodb/pkg/deployment/features"
3844 "github.com/arangodb/kube-arangodb/pkg/deployment/pod"
45+ "github.com/arangodb/kube-arangodb/pkg/deployment/resources"
3946 "github.com/arangodb/kube-arangodb/pkg/util/constants"
4047)
4148
4249var (
4350 cmdLifecycleProbe = & cobra.Command {
4451 Use : "probe" ,
45- Run : cmdLifecycleProbeCheck ,
52+ Run : cmdLifecycleProbeRun ,
53+ }
54+ cmdLifecycleProbeLiveness = & cobra.Command {
55+ Use : "liveness" ,
56+ Run : cmdLifecycleProbeRun ,
57+ }
58+ cmdLifecycleProbeReadiness = & cobra.Command {
59+ Use : "readiness" ,
60+ Run : cmdLifecycleProbeRun ,
61+ }
62+ cmdLifecycleProbeStartUp = & cobra.Command {
63+ Use : "startup" ,
64+ Run : cmdLifecycleProbeRun ,
4665 }
4766
4867 probeInput struct {
49- SSL bool
50- Auth bool
51- Endpoint string
52- JWTPath string
68+ Endpoint string
69+ JWTPath string
70+ ArangoDBVersion string
71+ ServerGroup string
72+ DeploymentMode string
73+ SSL bool
74+ Auth bool
75+ Enterprise bool
5376 }
5477)
5578
5679func init () {
5780 f := cmdLifecycleProbe .PersistentFlags ()
5881
82+ cmdLifecycleProbe .AddCommand (cmdLifecycleProbeLiveness )
83+ cmdLifecycleProbe .AddCommand (cmdLifecycleProbeReadiness )
84+ cmdLifecycleProbe .AddCommand (cmdLifecycleProbeStartUp )
85+
5986 f .BoolVarP (& probeInput .SSL , "ssl" , "" , false , "Determines if SSL is enabled" )
6087 f .BoolVarP (& probeInput .Auth , "auth" , "" , false , "Determines if authentication is enabled" )
61- f .StringVarP (& probeInput .Endpoint , "endpoint" , "" , "/_api/version" , "Endpoint (path) to call for lifecycle probe" )
88+ f .StringVarP (& probeInput .Endpoint , "endpoint" , "" , client .ServerApiVersionEndpoint , "Endpoint (path) to call for lifecycle probe" )
89+ f .MarkDeprecated ("endpoint" , "Endpoint is chosen automatically by the lifecycle process" )
6290 f .StringVarP (& probeInput .JWTPath , "jwt" , "" , shared .ClusterJWTSecretVolumeMountDir , "Path to the JWT tokens" )
91+ f .StringVar (& probeInput .ArangoDBVersion , "arangodb-version" , os .Getenv (resources .ArangoDBOverrideVersionEnv ),
92+ "Version of the ArangoDB" )
93+ f .StringVar (& probeInput .ServerGroup , "serverGroup" , os .Getenv (resources .ArangoDBOverrideServerGroupEnv ),
94+ "Name of the group where a server belongs to" )
95+ f .StringVar (& probeInput .DeploymentMode , "deploymentMode" , os .Getenv (resources .ArangoDBOverrideDeploymentModeEnv ),
96+ "A deployment mode (Cluster, Single, ActiveFailover)" )
97+ enterprise , _ := strconv .ParseBool (os .Getenv (resources .ArangoDBOverrideEnterpriseEnv ))
98+ f .BoolVar (& probeInput .Enterprise , "enterprise" , enterprise , "Determines if ArangoDB is enterprise" )
6399}
64100
65101func probeClient () * http.Client {
@@ -147,10 +183,10 @@ func addAuthHeader(req *http.Request) error {
147183 return nil
148184}
149185
150- func doRequest () (* http.Response , error ) {
186+ func doRequest (endpoint string ) (* http.Response , error ) {
151187 client := probeClient ()
152188
153- req , err := http .NewRequest (http .MethodGet , probeEndpoint (probeInput . Endpoint ), nil )
189+ req , err := http .NewRequest (http .MethodGet , probeEndpoint (endpoint ), nil )
154190 if err != nil {
155191 return nil , err
156192 }
@@ -162,22 +198,25 @@ func doRequest() (*http.Response, error) {
162198 return client .Do (req )
163199}
164200
165- func cmdLifecycleProbeCheck (cmd * cobra.Command , args []string ) {
166- if err := cmdLifecycleProbeCheckE ( ); err != nil {
201+ func cmdLifecycleProbeRun (cmd * cobra.Command , _ []string ) {
202+ if err := cmdLifecycleProbeRunE ( cmd ); err != nil {
167203 log .Error ().Err (err ).Msgf ("Fatal" )
168204 os .Exit (1 )
169205 }
170206}
171207
172- func cmdLifecycleProbeCheckE () error {
173- resp , err := doRequest ()
208+ func cmdLifecycleProbeRunE (cmd * cobra.Command ) error {
209+ endpoint := getEndpoint (api .ProbeType (cmd .Use ))
210+ resp , err := doRequest (endpoint )
174211 if err != nil {
175212 return err
176213 }
214+ if resp .Body != nil {
215+ defer resp .Body .Close ()
216+ }
177217
178218 if resp .StatusCode != http .StatusOK {
179219 if resp .Body != nil {
180- defer resp .Body .Close ()
181220 if data , err := ioutil .ReadAll (resp .Body ); err == nil {
182221 return errors .Errorf ("Unexpected code: %d - %s" , resp .StatusCode , string (data ))
183222 }
@@ -186,7 +225,51 @@ func cmdLifecycleProbeCheckE() error {
186225 return errors .Errorf ("Unexpected code: %d" , resp .StatusCode )
187226 }
188227
228+ if endpoint == client .ServerStatusEndpoint {
229+ // When server status endpoint is used then HTTP status code 200 is not enough.
230+ // The progress should be also checked.
231+ if resp .Body == nil {
232+ return errors .Errorf ("Expected body from the \" %s\" endpoint" , endpoint )
233+ }
234+ data , err := ioutil .ReadAll (resp .Body )
235+ if err != nil {
236+ return errors .Errorf ("Failed to read body from the \" %s\" endpoint" , endpoint )
237+ }
238+
239+ status := client.ServerStatus {}
240+ if err = json .Unmarshal (data , & status ); err != nil {
241+ return errors .Errorf ("Failed to unmarshal %s into server status" , string (data ))
242+ }
243+
244+ if progress , ok := status .GetProgress (); ! ok {
245+ return errors .Errorf ("server not ready: %s" , progress )
246+ }
247+ }
248+
189249 log .Info ().Msgf ("Check passed" )
190250
191251 return nil
192252}
253+
254+ // getEndpoint returns endpoint to the ArangoDB instance where readiness should be checked.
255+ func getEndpoint (probeType api.ProbeType ) string {
256+ if probeType == api .ProbeTypeReadiness {
257+ if probeInput .DeploymentMode == string (api .DeploymentModeActiveFailover ) {
258+ v := driver .Version (probeInput .ArangoDBVersion )
259+ if features .FailoverLeadership ().Supported (v , probeInput .Enterprise ) {
260+ return client .ServerApiVersionEndpoint
261+ }
262+ }
263+
264+ return client .ServerAvailabilityEndpoint
265+ }
266+
267+ if probeInput .ServerGroup == api .ServerGroupDBServersString {
268+ v := driver .Version (probeInput .ArangoDBVersion )
269+ if features .Version310 ().Supported (v , probeInput .Enterprise ) {
270+ return client .ServerStatusEndpoint
271+ }
272+ }
273+
274+ return client .ServerApiVersionEndpoint
275+ }
0 commit comments