From fcc6286d968df53cadf19dc402fb0cfe639f67b8 Mon Sep 17 00:00:00 2001 From: Michael Burman Date: Wed, 2 Dec 2020 13:32:56 +0200 Subject: [PATCH 1/3] Allow fetching schedules --- reaper/client.go | 37 ++++++++++++++++++++++++++++++++++++- reaper/types.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/reaper/client.go b/reaper/client.go index da9fdf5..0bddab5 100644 --- a/reaper/client.go +++ b/reaper/client.go @@ -11,6 +11,7 @@ import ( "net/url" "runtime" "sync" + "time" ) type ReaperClient interface { @@ -31,6 +32,10 @@ type ReaperClient interface { AddCluster(ctx context.Context, cluster string, seed string) error DeleteCluster(ctx context.Context, cluster string) error + + RepairSchedules(ctx context.Context) ([]RepairSchedule, error) + + RepairSchedulesPerCluster(ctx context.Context, clusterName string) ([]RepairSchedule, error) } type Client struct { @@ -43,7 +48,7 @@ func newClient(reaperBaseURL string) (*Client, error) { if baseURL, err := url.Parse(reaperBaseURL); err != nil { return nil, err } else { - return &Client{BaseURL: baseURL, UserAgent: "", httpClient: &http.Client{}}, nil + return &Client{BaseURL: baseURL, UserAgent: "", httpClient: &http.Client{Timeout: 3 * time.Second}}, nil } } @@ -217,6 +222,36 @@ func (c *Client) DeleteCluster(ctx context.Context, cluster string) error { return nil } +func (c *Client) RepairSchedules(ctx context.Context) ([]RepairSchedule, error) { + rel := &url.URL{Path: "/repair_schedule"} + return c.fetchRepairSchedules(ctx, rel) +} + +func (c *Client) RepairSchedulesPerCluster(ctx context.Context, clusterName string) ([]RepairSchedule, error) { + rel := &url.URL{Path: fmt.Sprintf("/repair_schedule/cluster/%s", clusterName)} + return c.fetchRepairSchedules(ctx, rel) +} + +func (c *Client) fetchRepairSchedules(ctx context.Context, rel *url.URL) ([]RepairSchedule, error) { + u := c.BaseURL.ResolveReference(rel) + req, err := http.NewRequest(http.MethodGet, u.String(), nil) + + if err != nil { + return nil, err + } + + schedules := make([]RepairSchedule, 0) + resp, err := c.doJsonRequest(ctx, req, &schedules) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, fmt.Errorf("Failed to fetch repair schedules: %v\n", resp.StatusCode) + } + + return schedules, nil +} + func (c *Client) doJsonRequest(ctx context.Context, req *http.Request, v interface{}) (*http.Response, error) { req.Header.Set("Accept", "application/json") return c.doRequest(ctx, req, v) diff --git a/reaper/types.go b/reaper/types.go index f081440..5aefee6 100644 --- a/reaper/types.go +++ b/reaper/types.go @@ -46,6 +46,39 @@ type GetClusterResult struct { Error error } +type RepairSchedule struct { + Id string `json:"id"` + State string `json:"state,omitempty"` + Intensity float64 `json:"intensity,omitempty"` + //private final UUID id; + // + //private final UUID repairUnitId; + //private final State state; + //private final int daysBetween; + //private final DateTime nextActivation; + //private final ImmutableList runHistory; + //@Deprecated private final int segmentCount; + //private final RepairParallelism repairParallelism; + //private final double intensity; + //private final DateTime creationTime; + //private final String owner; + //private final DateTime pauseTime; + //private final int segmentCountPerNode; + + //public enum State { + //ACTIVE, + //PAUSED, + //DELETED + //} + + //public enum RepairParallelism { + //SEQUENTIAL("sequential"), + //PARALLEL("parallel"), + //DATACENTER_AWARE("dc_parallel"); + + +} + // All the following types are used internally by the client and not part of the public API type clusterStatus struct { From 4842f5f84419b3b0bd43c8ce8b76d489aeea59c3 Mon Sep 17 00:00:00 2001 From: Michael Burman Date: Thu, 3 Dec 2020 17:00:07 +0200 Subject: [PATCH 2/3] More types --- reaper/types.go | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/reaper/types.go b/reaper/types.go index 5aefee6..5746b42 100644 --- a/reaper/types.go +++ b/reaper/types.go @@ -48,22 +48,15 @@ type GetClusterResult struct { type RepairSchedule struct { Id string `json:"id"` + Owner string `json:"owner,omitempty"` State string `json:"state,omitempty"` Intensity float64 `json:"intensity,omitempty"` - //private final UUID id; - // - //private final UUID repairUnitId; - //private final State state; - //private final int daysBetween; - //private final DateTime nextActivation; - //private final ImmutableList runHistory; - //@Deprecated private final int segmentCount; - //private final RepairParallelism repairParallelism; - //private final double intensity; - //private final DateTime creationTime; - //private final String owner; - //private final DateTime pauseTime; - //private final int segmentCountPerNode; + ClusterName string `json:"cluster_name,omitempty"` + KeyspaceName string `json:"keyspace_name,omitempty"` + RepairParallism string `json:"repair_parallelism,omitempty"` + IncrementalRepair bool `json:"incremental_repair,omitempty"` + ThreadCount int `json:"repair_thread_count,omitempty"` + UnitId string `json:"repair_unit_id,omitempty"` //public enum State { //ACTIVE, @@ -76,7 +69,32 @@ type RepairSchedule struct { //PARALLEL("parallel"), //DATACENTER_AWARE("dc_parallel"); - +/* +[ +{ + "id": "9ee7f6e0-3575-11eb-8fca-273b55edb18f", + "owner": "auto-scheduling", + "state": "ACTIVE", + "intensity": 0.8999999761581421, + "cluster_name": "k8ssandra", + "keyspace_name": "reaper_db", + "column_families": [], + "incremental_repair": false, + "segment_count": 0, + "repair_parallelism": "DATACENTER_AWARE", + "scheduled_days_between": 7, + "nodes": [], + "datacenters": [], + "blacklisted_tables": [], + "segment_count_per_node": 64, + "repair_thread_count": 1, + "repair_unit_id": "9ee6be60-3575-11eb-8fca-273b55edb18f", + "creation_time": "2020-12-03T14:41:25Z", + "pause_time": "2020-12-03T14:46:28Z", + "next_activation": "2020-12-10T14:46:25Z" +} +] + */ } // All the following types are used internally by the client and not part of the public API From db8ffff5250b39cfb08948478f60d7a1cd3abc8f Mon Sep 17 00:00:00 2001 From: Michael Burman Date: Tue, 15 Dec 2020 00:03:54 +0200 Subject: [PATCH 3/3] Rename RepairSchedulerPerCluster to ForCluster and add some more parsed json fields --- reaper/client.go | 40 +++++++++++------------ reaper/types.go | 82 +++++++++++++++--------------------------------- 2 files changed, 45 insertions(+), 77 deletions(-) diff --git a/reaper/client.go b/reaper/client.go index 0bddab5..386b64c 100644 --- a/reaper/client.go +++ b/reaper/client.go @@ -35,7 +35,7 @@ type ReaperClient interface { RepairSchedules(ctx context.Context) ([]RepairSchedule, error) - RepairSchedulesPerCluster(ctx context.Context, clusterName string) ([]RepairSchedule, error) + RepairSchedulesForCluster(ctx context.Context, clusterName string) ([]RepairSchedule, error) } type Client struct { @@ -181,7 +181,7 @@ func (c *Client) AddCluster(ctx context.Context, cluster string, seed string) er resp, err := c.httpClient.Do(req) if err != nil { select { - case <- ctx.Done(): + case <-ctx.Done(): return ctx.Err() default: } @@ -227,7 +227,7 @@ func (c *Client) RepairSchedules(ctx context.Context) ([]RepairSchedule, error) return c.fetchRepairSchedules(ctx, rel) } -func (c *Client) RepairSchedulesPerCluster(ctx context.Context, clusterName string) ([]RepairSchedule, error) { +func (c *Client) RepairSchedulesForCluster(ctx context.Context, clusterName string) ([]RepairSchedule, error) { rel := &url.URL{Path: fmt.Sprintf("/repair_schedule/cluster/%s", clusterName)} return c.fetchRepairSchedules(ctx, rel) } @@ -263,7 +263,7 @@ func (c *Client) doRequest(ctx context.Context, req *http.Request, v interface{} resp, err := c.httpClient.Do(req) if err != nil { select { - case <- ctx.Done(): + case <-ctx.Done(): return nil, ctx.Err() default: } @@ -284,19 +284,19 @@ func (c *Client) doRequest(ctx context.Context, req *http.Request, v interface{} func newCluster(state *clusterStatus) *Cluster { cluster := Cluster{ - Name: state.Name, - JmxUsername: state.JmxUsername, + Name: state.Name, + JmxUsername: state.JmxUsername, JmxPasswordSet: state.JmxPasswordSet, - Seeds: state.Seeds, - NodeState: NodeState{}, + Seeds: state.Seeds, + NodeState: NodeState{}, } for _, gs := range state.NodeStatus.EndpointStates { gossipState := GossipState{ - SourceNode: gs.SourceNode, + SourceNode: gs.SourceNode, EndpointNames: gs.EndpointNames, - TotalLoad: gs.TotalLoad, - DataCenters: map[string]DataCenterState{}, + TotalLoad: gs.TotalLoad, + DataCenters: map[string]DataCenterState{}, } for dc, dcStateInternal := range gs.Endpoints { dcState := DataCenterState{Name: dc, Racks: map[string]RackState{}} @@ -304,15 +304,15 @@ func newCluster(state *clusterStatus) *Cluster { rackState := RackState{Name: rack} for _, ep := range endpoints { endpoint := EndpointState{ - Endpoint: ep.Endpoint, - DataCenter: ep.DataCenter, - Rack: ep.Rack, - HostId: ep.HostId, - Status: ep.Status, - Severity: ep.Severity, + Endpoint: ep.Endpoint, + DataCenter: ep.DataCenter, + Rack: ep.Rack, + HostId: ep.HostId, + Status: ep.Status, + Severity: ep.Severity, ReleaseVersion: ep.ReleaseVersion, - Tokens: ep.Tokens, - Load: ep.Load, + Tokens: ep.Tokens, + Load: ep.Load, } rackState.Endpoints = append(rackState.Endpoints, endpoint) } @@ -332,4 +332,4 @@ func getBodyAsString(resp *http.Response) (string, error) { return "", err } return string(body), nil -} \ No newline at end of file +} diff --git a/reaper/types.go b/reaper/types.go index 5746b42..39b2655 100644 --- a/reaper/types.go +++ b/reaper/types.go @@ -1,5 +1,7 @@ package reaper +import "time" + type Cluster struct { Name string JmxUsername string @@ -47,54 +49,20 @@ type GetClusterResult struct { } type RepairSchedule struct { - Id string `json:"id"` - Owner string `json:"owner,omitempty"` - State string `json:"state,omitempty"` - Intensity float64 `json:"intensity,omitempty"` - ClusterName string `json:"cluster_name,omitempty"` - KeyspaceName string `json:"keyspace_name,omitempty"` - RepairParallism string `json:"repair_parallelism,omitempty"` - IncrementalRepair bool `json:"incremental_repair,omitempty"` - ThreadCount int `json:"repair_thread_count,omitempty"` - UnitId string `json:"repair_unit_id,omitempty"` - - //public enum State { - //ACTIVE, - //PAUSED, - //DELETED - //} - - //public enum RepairParallelism { - //SEQUENTIAL("sequential"), - //PARALLEL("parallel"), - //DATACENTER_AWARE("dc_parallel"); - -/* -[ -{ - "id": "9ee7f6e0-3575-11eb-8fca-273b55edb18f", - "owner": "auto-scheduling", - "state": "ACTIVE", - "intensity": 0.8999999761581421, - "cluster_name": "k8ssandra", - "keyspace_name": "reaper_db", - "column_families": [], - "incremental_repair": false, - "segment_count": 0, - "repair_parallelism": "DATACENTER_AWARE", - "scheduled_days_between": 7, - "nodes": [], - "datacenters": [], - "blacklisted_tables": [], - "segment_count_per_node": 64, - "repair_thread_count": 1, - "repair_unit_id": "9ee6be60-3575-11eb-8fca-273b55edb18f", - "creation_time": "2020-12-03T14:41:25Z", - "pause_time": "2020-12-03T14:46:28Z", - "next_activation": "2020-12-10T14:46:25Z" -} -] - */ + Id string `json:"id"` + Owner string `json:"owner,omitempty"` + State string `json:"state,omitempty"` + Intensity float64 `json:"intensity,omitempty"` + ClusterName string `json:"cluster_name,omitempty"` + KeyspaceName string `json:"keyspace_name,omitempty"` + RepairParallism string `json:"repair_parallelism,omitempty"` + IncrementalRepair bool `json:"incremental_repair,omitempty"` + ThreadCount int `json:"repair_thread_count,omitempty"` + UnitId string `json:"repair_unit_id,omitempty"` + DaysBetween int `json:"scheduled_days_between,omitempty"` + Created time.Time `json:"creation_time,omitempty"` + Paused time.Time `json:"pause_time,omitempty"` + NextActivation time.Time `json:"next_activation,omitempty"` } // All the following types are used internally by the client and not part of the public API @@ -112,20 +80,20 @@ type nodeStatus struct { } type gossipStatus struct { - SourceNode string `json:"sourceNode"` + SourceNode string `json:"sourceNode"` EndpointNames []string `json:"endpointNames,omitempty"` - TotalLoad float64 `json:"totalLoad,omitempty"` + TotalLoad float64 `json:"totalLoad,omitempty"` Endpoints map[string]map[string][]endpointStatus } type endpointStatus struct { - Endpoint string `json:"endpoint"` - DataCenter string `json:"dc"` - Rack string `json:"rack"` - HostId string `json:"hostId"` - Status string `json:"status"` + Endpoint string `json:"endpoint"` + DataCenter string `json:"dc"` + Rack string `json:"rack"` + HostId string `json:"hostId"` + Status string `json:"status"` Severity float64 `json:"severity"` - ReleaseVersion string `json:"releaseVersion"` - Tokens string `json:"tokens"` + ReleaseVersion string `json:"releaseVersion"` + Tokens string `json:"tokens"` Load float64 `json:"load"` }