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

Implementation of cback-http-service #3153

Closed
wants to merge 54 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
7a70a19
Creating skeleton for http
Aug 2, 2022
071362c
Adding to loader
Aug 2, 2022
5858794
Created skeleton of HTTP service and GET functions
Aug 4, 2022
0781eaf
Amendments to router init function
Aug 4, 2022
b944938
Change to chi router paths
Aug 8, 2022
60f70c7
Added new function to make requests to cback API
Aug 9, 2022
812d97d
Overhaul of /restore/restore_id function
Aug 9, 2022
3eb8a82
POST Function added, along with utility functions
Aug 10, 2022
6b9da73
Returning Errors
Aug 10, 2022
70d3c1a
Testing features for input validation
Aug 10, 2022
bfe4ffb
Further input-validation
Aug 10, 2022
7ec0a15
Changing APIURL in configuration
Aug 11, 2022
3383167
Adding error handling with StatusCodes
Aug 11, 2022
2f66a04
Fix for incorrect path input
Aug 11, 2022
7e222b4
Further error handling
Aug 11, 2022
7d13f7b
Futher additions for error handling
Aug 11, 2022
b38a393
removal of redundant code
Aug 12, 2022
23a5dc5
Added changelog file
Aug 15, 2022
36c42d7
Fix of issues flagged by hound bot
Aug 15, 2022
9165f65
Minor change with error checking
Aug 15, 2022
b084bbb
Fixing Changelog
Aug 15, 2022
fda6634
Changes to changelog
Aug 15, 2022
0ff3911
Changing errors
Aug 16, 2022
ae1e531
Adding Licenses
Aug 17, 2022
05ebac7
Fixing linting errors
Aug 17, 2022
c9a0950
Creating skeleton for http
Aug 2, 2022
cd25c2f
Adding to loader
Aug 2, 2022
4e8b359
Created skeleton of HTTP service and GET functions
Aug 4, 2022
8cdbf20
Amendments to router init function
Aug 4, 2022
ecebaee
Change to chi router paths
Aug 8, 2022
1d59e09
Added new function to make requests to cback API
Aug 9, 2022
57a5baa
Overhaul of /restore/restore_id function
Aug 9, 2022
ee04739
POST Function added, along with utility functions
Aug 10, 2022
6eaaf86
Returning Errors
Aug 10, 2022
2ad7caa
Testing features for input validation
Aug 10, 2022
5cda5e2
Further input-validation
Aug 10, 2022
501ff82
Changing APIURL in configuration
Aug 11, 2022
fe617f5
Adding error handling with StatusCodes
Aug 11, 2022
634f042
Fix for incorrect path input
Aug 11, 2022
57e89df
Further error handling
Aug 11, 2022
aa5f6a2
Futher additions for error handling
Aug 11, 2022
87e8978
removal of redundant code
Aug 12, 2022
9355c20
Added changelog file
Aug 15, 2022
4254111
Fix of issues flagged by hound bot
Aug 15, 2022
9f0153a
Minor change with error checking
Aug 15, 2022
2246e53
Fixing Changelog
Aug 15, 2022
4951063
Changes to changelog
Aug 15, 2022
ccd350a
Changing errors
Aug 16, 2022
c80cfbf
Adding Licenses
Aug 17, 2022
a4b4cf1
Fixing linting errors
Aug 17, 2022
8e88efa
Merge branch 'cback-http' of https://github.com/KyleFearne/reva into …
Aug 18, 2022
524c193
Removal of cback storage driver
Aug 18, 2022
96536f3
Adding returns after error check
Aug 19, 2022
9d5ce94
Added switch after calling getRequest to return different error codes
Aug 19, 2022
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
5 changes: 5 additions & 0 deletions changelog/unreleased/enchancement-cback-http-service.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Enhancement: Implementation of HTTP Service for cback

This implementation allows for creation of new restore jobs, as well as the ability to GET information regarding particular jobs

https://github.com/cs3org/reva/pull/3153
5 changes: 0 additions & 5 deletions changelog/unreleased/enhancement-cback-storage-driver.md

This file was deleted.

320 changes: 320 additions & 0 deletions internal/http/services/cback/cback.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,320 @@
// Copyright 2018-2021 CERN
//
// 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.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

package cback

import (
"bytes"
"encoding/json"
"io"
"net/http"

ctxpkg "github.com/cs3org/reva/pkg/ctx"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/rhttp"
"github.com/cs3org/reva/pkg/rhttp/global"
"github.com/go-chi/chi/v5"
"github.com/mitchellh/mapstructure"
"github.com/rs/zerolog"
)

type requestTemp struct {
BackupID int `json:"backup_id"`
Pattern string `json:"pattern"`
Snapshot string `json:"snapshot"`
// destination string
// enabled bool
// date string
}

func init() {
global.Register("cback", New)
}

// New returns a new helloworld service
func New(m map[string]interface{}, log *zerolog.Logger) (global.Service, error) {
conf := &config{}
if err := mapstructure.Decode(m, conf); err != nil {
return nil, err
}

conf.init()
r := chi.NewRouter()
s := &svc{
conf: conf,
router: r,
client: rhttp.GetHTTPClient(),
}

if err := s.routerInit(); err != nil {
return nil, err
}

return s, nil

}

// Close performs cleanup.
func (s *svc) Close() error {
return nil
}

type config struct {
Prefix string `mapstructure:"prefix"`
ImpersonatorToken string `mapstructure:"token"`
APIURL string `mapstructure:"api_url"`
}

func (c *config) init() {

if c.Prefix == "" {
c.Prefix = "cback"
}
}

type svc struct {
conf *config
router *chi.Mux
client *http.Client
}

func (s *svc) Prefix() string {
return s.conf.Prefix
}

func (s *svc) Unprotected() []string {
return nil
}

func (s *svc) routerInit() error {

s.router.Get("/restore", s.handleListJobs)
s.router.Post("/restore", s.handleRestoreID)
s.router.Get("/restore/{restore_id}", s.handleRestoreStatus)
return nil
}

func (s *svc) handleRestoreID(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
user, inContext := ctxpkg.ContextGetUser(ctx)

if !inContext {
http.Error(w, errtypes.UserRequired("no user found in context").Error(), http.StatusInternalServerError)
return
}

url := s.conf.APIURL + "/restores/"
var ssID, searchPath string

path := r.URL.Query().Get("path")

if path == "" {
http.Error(w, "The id query parameter is missing", http.StatusBadRequest)
return
}

resp, err := s.matchBackups(user.Username, path)

if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

if resp == nil {
http.Error(w, errtypes.NotFound("cback: not found").Error(), http.StatusInternalServerError)
return
}

snapshotList, err := s.listSnapshots(user.Username, resp.ID)

if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

if resp.Substring != "" {
ssID, searchPath = s.pathTrimmer(snapshotList, resp)

if ssID == "" {
http.Error(w, errtypes.NotFound("cback: snapshot not found").Error(), http.StatusNotFound)
return
}

err = s.checkFileType(resp.ID, ssID, user.Username, searchPath, resp.Source)

if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}

structbody := &requestTemp{
BackupID: resp.ID,
Snapshot: ssID,
Pattern: searchPath,
}

jbody, err := json.Marshal(structbody)

if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

resp, err := s.getRequest(user.Username, url, http.MethodPost, bytes.NewBuffer(jbody))

if err != nil {
switch err {
case errtypes.NotFound("cback: resource not found"):
http.Error(w, err.Error(), http.StatusNotFound)
return
case errtypes.PermissionDenied("cback: user has no permissions to get the backup"):
http.Error(w, err.Error(), http.StatusForbidden)
return
case errtypes.BadRequest("cback"):
http.Error(w, err.Error(), http.StatusBadRequest)
return
default:
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}

defer resp.Close()

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
err = json.NewEncoder(w).Encode(resp)

if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
KyleFearne marked this conversation as resolved.
Show resolved Hide resolved
return
}

if _, err := io.Copy(w, resp); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

} else {

err = errtypes.NotFound("cback: resource not found")
http.Error(w, err.Error(), http.StatusNotFound)
return
}
}

func (s *svc) handleListJobs(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
user, inContext := ctxpkg.ContextGetUser(ctx)

if !inContext {
http.Error(w, errtypes.UserRequired("no user found in context").Error(), http.StatusInternalServerError)
return
}

url := s.conf.APIURL + "/restores/"

resp, err := s.getRequest(user.Username, url, http.MethodGet, nil)

if err != nil {
switch err {
case errtypes.NotFound("cback: resource not found"):
http.Error(w, err.Error(), http.StatusNotFound)
return
case errtypes.PermissionDenied("cback: user has no permissions to get the backup"):
http.Error(w, err.Error(), http.StatusForbidden)
return
case errtypes.BadRequest("cback"):
http.Error(w, err.Error(), http.StatusBadRequest)
return
default:
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}

defer resp.Close()

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
err = json.NewEncoder(w).Encode(resp)

if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
KyleFearne marked this conversation as resolved.
Show resolved Hide resolved
return
}

if _, err := io.Copy(w, resp); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

}

func (s *svc) handleRestoreStatus(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
user, inContext := ctxpkg.ContextGetUser(ctx)

if !inContext {
http.Error(w, errtypes.UserRequired("no user found in context").Error(), http.StatusInternalServerError)
return
}

restoreID := chi.URLParam(r, "restore_id")

url := s.conf.APIURL + "/restores/" + restoreID
resp, err := s.getRequest(user.Username, url, http.MethodGet, nil)

if err != nil {
switch err {
case errtypes.NotFound("cback: resource not found"):
http.Error(w, err.Error(), http.StatusNotFound)
return
case errtypes.PermissionDenied("cback: user has no permissions to get the backup"):
http.Error(w, err.Error(), http.StatusForbidden)
return
case errtypes.BadRequest("cback"):
http.Error(w, err.Error(), http.StatusBadRequest)
return
default:
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}

defer resp.Close()

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
err = json.NewEncoder(w).Encode(resp)

if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
KyleFearne marked this conversation as resolved.
Show resolved Hide resolved
}

if _, err := io.Copy(w, resp); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}

func (s *svc) Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
s.router.ServeHTTP(w, r)
})
}
Loading