feat(pkger): add create service and http functionality for a package
supports as of this just the basic metadata being setup on the initial postpull/15758/head
parent
33e87b74bb
commit
848875e64b
7
go.mod
7
go.mod
|
@ -27,12 +27,13 @@ require (
|
|||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 // indirect
|
||||
github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493 // indirect
|
||||
github.com/go-chi/chi v4.0.2+incompatible
|
||||
github.com/gogo/protobuf v1.2.1
|
||||
github.com/golang/gddo v0.0.0-20181116215533-9bd4a3295021
|
||||
github.com/golang/protobuf v1.3.2
|
||||
github.com/golang/snappy v0.0.1
|
||||
github.com/google/btree v1.0.0
|
||||
github.com/google/go-cmp v0.3.0
|
||||
github.com/google/go-cmp v0.3.1
|
||||
github.com/google/go-github v17.0.0+incompatible
|
||||
github.com/goreleaser/goreleaser v0.97.0
|
||||
github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c // indirect
|
||||
|
@ -43,12 +44,14 @@ require (
|
|||
github.com/influxdata/influxql v0.0.0-20180925231337-1cbfca8e56b6
|
||||
github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368
|
||||
github.com/jessevdk/go-flags v1.4.0
|
||||
github.com/jsteenb2/testttp v0.0.0-20190807043343-249d5435f72f
|
||||
github.com/jsternberg/zap-logfmt v1.2.0
|
||||
github.com/julienschmidt/httprouter v1.2.0
|
||||
github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef
|
||||
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
|
||||
github.com/kevinburke/go-bindata v3.11.0+incompatible
|
||||
github.com/mattn/go-isatty v0.0.4
|
||||
github.com/mattn/go-colorable v0.1.4 // indirect
|
||||
github.com/mattn/go-isatty v0.0.8
|
||||
github.com/mattn/go-zglob v0.0.1 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1
|
||||
github.com/mna/pigeon v1.0.1-0.20180808201053-bb0192cfc2ae
|
||||
|
|
11
go.sum
11
go.sum
|
@ -123,6 +123,8 @@ github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 h1:Ujru
|
|||
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493 h1:OTanQnFt0bi5iLFSdbEVA/idR6Q2WhCm+deb7ir2CcM=
|
||||
github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
||||
github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs=
|
||||
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
|
@ -163,6 +165,8 @@ github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
|||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
|
@ -258,6 +262,8 @@ github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht
|
|||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/jsteenb2/testttp v0.0.0-20190807043343-249d5435f72f h1:/yuIWaHCxcz1pivurAmhBjVQpUAfJR1JHWWVeviSUBc=
|
||||
github.com/jsteenb2/testttp v0.0.0-20190807043343-249d5435f72f/go.mod h1:b4xqoUXV10gDTau9rOyBPcgYYxuCISP6BYynbRuJKBc=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jsternberg/zap-logfmt v1.2.0 h1:1v+PK4/B48cy8cfQbxL4FmmNZrjnIMr2BsnyEmXqv2o=
|
||||
github.com/jsternberg/zap-logfmt v1.2.0/go.mod h1:kz+1CUmCutPWABnNkOu9hOHKdT2q3TDYCcsFy9hpqb0=
|
||||
|
@ -292,9 +298,13 @@ github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDe
|
|||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4=
|
||||
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104 h1:d8RFOZ2IiFtFWBcKEHAFYJcPTf0wY5q0exFNJZVWa1U=
|
||||
|
@ -533,6 +543,7 @@ golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqYSEQ0KWqdWLu3xuZJts=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
package pkger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/chi/middleware"
|
||||
"github.com/influxdata/influxdb"
|
||||
)
|
||||
|
||||
type HTTPServer struct {
|
||||
r chi.Router
|
||||
influxdb.HTTPErrorHandler
|
||||
svc *Service
|
||||
}
|
||||
|
||||
func NewHTTPServer(errHandler influxdb.HTTPErrorHandler, svc *Service) *HTTPServer {
|
||||
svr := &HTTPServer{
|
||||
HTTPErrorHandler: errHandler,
|
||||
svc: svc,
|
||||
}
|
||||
|
||||
r := chi.NewRouter()
|
||||
r.Use(middleware.RequestID)
|
||||
r.Use(middleware.RealIP)
|
||||
r.Use(middleware.Recoverer)
|
||||
|
||||
r.Route("/api/v2/packages", func(r chi.Router) {
|
||||
r.Use(middleware.SetHeader("Content-Type", "application/json; charset=utf-8"))
|
||||
|
||||
r.Post("/", svr.createPkg)
|
||||
})
|
||||
|
||||
svr.r = r
|
||||
return svr
|
||||
}
|
||||
|
||||
func (s *HTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
s.r.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
type ReqCreatePkg struct {
|
||||
PkgName string `json:"pkgName"`
|
||||
PkgDescription string `json:"pkgDescription"`
|
||||
PkgVersion string `json:"pkgVersion"`
|
||||
}
|
||||
|
||||
type RespCreatePkg struct {
|
||||
Package *Pkg `json:"package"`
|
||||
}
|
||||
|
||||
func (s *HTTPServer) createPkg(w http.ResponseWriter, r *http.Request) {
|
||||
var reqBody ReqCreatePkg
|
||||
if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil {
|
||||
s.HandleHTTPError(r.Context(), newDecodeErr(err), w)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
newPkg, err := s.svc.CreatePkg(r.Context(),
|
||||
WithMetadata(Metadata{
|
||||
Description: reqBody.PkgDescription,
|
||||
Name: reqBody.PkgName,
|
||||
Version: reqBody.PkgVersion,
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
s.HandleHTTPError(r.Context(), err, w)
|
||||
return
|
||||
}
|
||||
|
||||
s.encResp(r.Context(), w, http.StatusOK, RespCreatePkg{
|
||||
Package: newPkg,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *HTTPServer) encResp(ctx context.Context, w http.ResponseWriter, code int, res interface{}) {
|
||||
w.WriteHeader(code)
|
||||
if err := json.NewEncoder(w).Encode(res); err != nil {
|
||||
s.HandleHTTPError(ctx, err, w)
|
||||
}
|
||||
}
|
||||
|
||||
func newDecodeErr(err error) *influxdb.Error {
|
||||
return &influxdb.Error{
|
||||
Msg: fmt.Sprintf("unable to marshal JSON; Err: %v", err),
|
||||
Code: influxdb.EInvalid,
|
||||
Err: err,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package pkger_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/influxdb/http"
|
||||
"github.com/influxdata/influxdb/pkger"
|
||||
"github.com/jsteenb2/testttp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestHTTPServer(t *testing.T) {
|
||||
t.Run("create pkg", func(t *testing.T) {
|
||||
t.Run("should successfully return with valid req body", func(t *testing.T) {
|
||||
svr := pkger.NewHTTPServer(http.ErrorHandler(0), new(pkger.Service))
|
||||
|
||||
body := newReqBody(t, pkger.ReqCreatePkg{
|
||||
PkgName: "name1",
|
||||
PkgDescription: "desc1",
|
||||
PkgVersion: "v1",
|
||||
})
|
||||
|
||||
testttp.POST(t, svr, "/api/v2/packages", body,
|
||||
testttp.StatusOK(),
|
||||
testttp.Resp(func(t *testing.T, w *httptest.ResponseRecorder) {
|
||||
var resp pkger.RespCreatePkg
|
||||
decodeBody(t, w.Body, &resp)
|
||||
|
||||
pkg := resp.Package
|
||||
assert.Equal(t, pkger.APIVersion, pkg.APIVersion)
|
||||
assert.Equal(t, "package", pkg.Kind)
|
||||
|
||||
meta := pkg.Metadata
|
||||
assert.Equal(t, "name1", meta.Name)
|
||||
assert.Equal(t, "desc1", meta.Description)
|
||||
assert.Equal(t, "v1", meta.Version)
|
||||
|
||||
assert.NotNil(t, pkg.Spec.Resources)
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func decodeBody(t *testing.T, r io.Reader, v interface{}) {
|
||||
t.Helper()
|
||||
|
||||
if err := json.NewDecoder(r).Decode(v); err != nil {
|
||||
require.FailNow(t, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func newReqBody(t *testing.T, v interface{}) *bytes.Buffer {
|
||||
t.Helper()
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := json.NewEncoder(&buf).Encode(v); err != nil {
|
||||
require.FailNow(t, "unexpected json encoding error", err)
|
||||
}
|
||||
return &buf
|
||||
}
|
|
@ -12,6 +12,9 @@ import (
|
|||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// APIVersion marks the current APIVersion for influx packages.
|
||||
const APIVersion = "0.1.0"
|
||||
|
||||
// Service provides the pkger business logic including all the dependencies to make
|
||||
// this resource sausage.
|
||||
type Service struct {
|
||||
|
@ -37,6 +40,39 @@ func NewService(l *zap.Logger, bucketSVC influxdb.BucketService, labelSVC influx
|
|||
return &svc
|
||||
}
|
||||
|
||||
// CreatePkgSetFn is a functional input for setting the pkg fields.
|
||||
type CreatePkgSetFn func(ctx context.Context, pkg *Pkg) error
|
||||
|
||||
// WithMetadata sets the metadata on the pkg in a CreatePkg call.
|
||||
func WithMetadata(meta Metadata) CreatePkgSetFn {
|
||||
return func(ctx context.Context, pkg *Pkg) error {
|
||||
pkg.Metadata = meta
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// CreatePkg will produce a pkg from the parameters provided.
|
||||
func (s *Service) CreatePkg(ctx context.Context, setters ...CreatePkgSetFn) (*Pkg, error) {
|
||||
pkg := &Pkg{
|
||||
APIVersion: APIVersion,
|
||||
Kind: kindPackage.String(),
|
||||
Spec: struct {
|
||||
Resources []Resource `yaml:"resources" json:"resources"`
|
||||
}{
|
||||
Resources: []Resource{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, setter := range setters {
|
||||
err := setter(ctx, pkg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return pkg, nil
|
||||
}
|
||||
|
||||
// DryRun provides a dry run of the pkg application. The pkg will be marked verified
|
||||
// for later calls to Apply. This func will be run on an Apply if it has not been run
|
||||
// already.
|
||||
|
|
|
@ -494,4 +494,22 @@ func TestService(t *testing.T) {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("CreatePkg", func(t *testing.T) {
|
||||
t.Run("with metadata sets the new pkgs metadata", func(t *testing.T) {
|
||||
svc := new(Service)
|
||||
|
||||
expectedMeta := Metadata{
|
||||
Description: "desc",
|
||||
Name: "name",
|
||||
Version: "v1",
|
||||
}
|
||||
pkg, err := svc.CreatePkg(context.TODO(), WithMetadata(expectedMeta))
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, APIVersion, pkg.APIVersion)
|
||||
assert.Equal(t, expectedMeta, pkg.Metadata)
|
||||
assert.NotNil(t, pkg.Spec.Resources)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue