From 70ecebb769b31b033bd5af1e41cf80f481bed1d2 Mon Sep 17 00:00:00 2001 From: Jarek Kowalski Date: Sat, 16 Jun 2018 08:46:56 -0700 Subject: [PATCH] added HTTP API to list policies --- internal/server/api_policy_list.go | 42 ++++++++++++++++++++++++++++ internal/server/api_snapshot_list.go | 39 ++++++++++++++++++++++---- internal/server/api_sources_list.go | 7 ++++- internal/server/server.go | 1 + snapshot/policy.go | 12 ++++++++ 5 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 internal/server/api_policy_list.go diff --git a/internal/server/api_policy_list.go b/internal/server/api_policy_list.go new file mode 100644 index 000000000..f7d24e1c5 --- /dev/null +++ b/internal/server/api_policy_list.go @@ -0,0 +1,42 @@ +package server + +import ( + "net/http" + + "github.com/kopia/kopia/snapshot" +) + +type policyListEntry struct { + ID string `json:"id"` + Source snapshot.SourceInfo `json:"source"` + Policy *snapshot.Policy `json:"policy"` +} + +type policyListResponse struct { + Policies []*policyListEntry `json:"policies"` +} + +func (s *Server) handlePolicyList(r *http.Request) (interface{}, *apiError) { + policies, err := s.policyManager.ListPolicies() + if err != nil { + return nil, internalServerError(err) + } + + resp := &policyListResponse{ + Policies: []*policyListEntry{}, + } + + for _, pol := range policies { + src := pol.Source() + if !sourceMatchesURLFilter(src, r.URL.Query()) { + continue + } + resp.Policies = append(resp.Policies, &policyListEntry{ + ID: pol.ID(), + Source: src, + Policy: pol, + }) + } + + return resp, nil +} diff --git a/internal/server/api_snapshot_list.go b/internal/server/api_snapshot_list.go index 2d29e0122..ca2ffcd8c 100644 --- a/internal/server/api_snapshot_list.go +++ b/internal/server/api_snapshot_list.go @@ -2,6 +2,8 @@ import ( "net/http" + "net/url" + "strings" "time" "github.com/kopia/kopia/fs" @@ -31,15 +33,21 @@ func (s *Server) handleSourceSnapshotList(r *http.Request) (interface{}, *apiErr return nil, internalServerError(err) } - resp := &snapshotListResponse{} - + resp := &snapshotListResponse{ + Snapshots: []*snapshotListEntry{}, + } groups := snapshot.GroupBySource(manifests) - for _, grp := range groups { - pol, err := s.policyManager.GetEffectivePolicy(grp[0].Source) + first := grp[0] + if !sourceMatchesURLFilter(first.Source, r.URL.Query()) { + continue + } + + pol, err := s.policyManager.GetEffectivePolicy(first.Source) if err == nil { pol.RetentionPolicy.ComputeRetentionReasons(grp) } + for _, m := range grp { resp.Snapshots = append(resp.Snapshots, convertSnapshotManifest(m)) } @@ -48,8 +56,22 @@ func (s *Server) handleSourceSnapshotList(r *http.Request) (interface{}, *apiErr return resp, nil } +func sourceMatchesURLFilter(src snapshot.SourceInfo, query url.Values) bool { + if v := query.Get("host"); v != "" && src.Host != v { + return false + } + if v := query.Get("userName"); v != "" && src.UserName != v { + return false + } + if v := query.Get("path"); v != "" && !strings.Contains(src.Path, v) { + return false + } + + return true +} + func convertSnapshotManifest(m *snapshot.Manifest) *snapshotListEntry { - return &snapshotListEntry{ + e := &snapshotListEntry{ ID: m.ID, Source: m.Source, Description: m.Description, @@ -57,7 +79,12 @@ func convertSnapshotManifest(m *snapshot.Manifest) *snapshotListEntry { EndTime: m.EndTime, IncompleteReason: m.IncompleteReason, RootEntry: m.RootObjectID().String(), - Summary: m.RootEntry.DirSummary, RetentionReasons: m.RetentionReasons, } + + if re := m.RootEntry; re != nil { + e.Summary = re.DirSummary + } + + return e } diff --git a/internal/server/api_sources_list.go b/internal/server/api_sources_list.go index 54015d8e8..c1b3517bf 100644 --- a/internal/server/api_sources_list.go +++ b/internal/server/api_sources_list.go @@ -10,9 +10,14 @@ type sourcesListResponse struct { } func (s *Server) handleSourcesList(r *http.Request) (interface{}, *apiError) { - resp := &sourcesListResponse{} + resp := &sourcesListResponse{ + Sources: []sourceStatus{}, + } for _, v := range s.sourceManagers { + if !sourceMatchesURLFilter(v.src, r.URL.Query()) { + continue + } resp.Sources = append(resp.Sources, v.Status()) } diff --git a/internal/server/server.go b/internal/server/server.go index abca95b72..7010640e4 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -31,6 +31,7 @@ func (s *Server) APIHandlers() http.Handler { p.Get("/api/v1/status", s.handleAPI(s.handleStatus)) p.Get("/api/v1/sources", s.handleAPI(s.handleSourcesList)) p.Get("/api/v1/snapshots", s.handleAPI(s.handleSourceSnapshotList)) + p.Get("/api/v1/policies", s.handleAPI(s.handlePolicyList)) return p } diff --git a/snapshot/policy.go b/snapshot/policy.go index 7e2cfeb59..222052388 100644 --- a/snapshot/policy.go +++ b/snapshot/policy.go @@ -31,6 +31,18 @@ func (p *Policy) String() string { return buf.String() } +func (p *Policy) ID() string { + return p.Labels["id"] +} + +func (p *Policy) Source() SourceInfo { + return SourceInfo{ + Host: p.Labels["hostname"], + UserName: p.Labels["username"], + Path: p.Labels["path"], + } +} + // MergePolicies computes the policy by applying the specified list of policies in order. func MergePolicies(policies []*Policy) *Policy { var merged Policy