diff --git a/buf.gen.yaml b/buf.gen.yaml
new file mode 100644
index 00000000..cacaaf8b
--- /dev/null
+++ b/buf.gen.yaml
@@ -0,0 +1,13 @@
+version: v1
+plugins:
+ - name: go
+ out: ./server
+ opt: paths=source_relative
+ - name: go-grpc
+ out: ./server
+ opt: paths=source_relative
+ - name: grpc-gateway
+ out: ./server
+ opt: paths=source_relative
+ - name: openapiv2
+ out: ./server
diff --git a/server/api/adapter.go b/server/api/adapter.go
new file mode 100644
index 00000000..21a5adbe
--- /dev/null
+++ b/server/api/adapter.go
@@ -0,0 +1,47 @@
+package api
+
+import (
+ "github.com/odpf/stencil/server/models"
+ stencilv1 "github.com/odpf/stencil/server/odpf/stencil/v1"
+ "github.com/odpf/stencil/server/snapshot"
+)
+
+func fromProtoToSnapshot(g *stencilv1.Snapshot) *snapshot.Snapshot {
+ return &snapshot.Snapshot{
+ ID: g.GetId(),
+ Namespace: g.GetNamespace(),
+ Name: g.GetName(),
+ Version: g.GetVersion(),
+ Latest: g.GetLatest(),
+ }
+}
+
+func fromSnapshotToProto(g *snapshot.Snapshot) *stencilv1.Snapshot {
+ return &stencilv1.Snapshot{
+ Id: g.ID,
+ Namespace: g.Namespace,
+ Name: g.Name,
+ Version: g.Version,
+ Latest: g.Latest,
+ }
+}
+
+func toRulesList(r *stencilv1.Checks) []string {
+ var rules []string
+ if r == nil {
+ return rules
+ }
+ for _, rule := range r.Except {
+ rules = append(rules, rule.String())
+ }
+ return rules
+}
+
+func toFileDownloadRequest(g *stencilv1.DownloadDescriptorRequest) *models.FileDownloadRequest {
+ return &models.FileDownloadRequest{
+ Namespace: g.Namespace,
+ Name: g.Name,
+ Version: g.Version,
+ FullNames: g.GetFullnames(),
+ }
+}
diff --git a/server/api/api.go b/server/api/api.go
index 714bf4f8..90fe8c79 100644
--- a/server/api/api.go
+++ b/server/api/api.go
@@ -3,7 +3,9 @@ package api
import (
"context"
+ stencilv1 "github.com/odpf/stencil/server/odpf/stencil/v1"
"github.com/odpf/stencil/server/snapshot"
+ "google.golang.org/grpc/health/grpc_health_v1"
)
//StoreService Service Interface for storage and validation
@@ -16,14 +18,16 @@ type StoreService interface {
// MetadataService Service Interface for metadata store
type MetadataService interface {
Exists(context.Context, *snapshot.Snapshot) bool
- ListNames(context.Context, string) ([]string, error)
- ListVersions(context.Context, string, string) ([]string, error)
- GetSnapshot(context.Context, string, string, string, bool) (*snapshot.Snapshot, error)
+ List(context.Context, *snapshot.Snapshot) ([]*snapshot.Snapshot, error)
+ GetSnapshotByFields(context.Context, string, string, string, bool) (*snapshot.Snapshot, error)
+ GetSnapshotByID(context.Context, int64) (*snapshot.Snapshot, error)
UpdateLatestVersion(context.Context, *snapshot.Snapshot) error
}
//API holds all handlers
type API struct {
+ stencilv1.UnimplementedStencilServiceServer
+ grpc_health_v1.UnimplementedHealthServer
Store StoreService
Metadata MetadataService
}
diff --git a/server/api/api_test.go b/server/api/api_test.go
index e93dead4..74bfe183 100644
--- a/server/api/api_test.go
+++ b/server/api/api_test.go
@@ -1,15 +1,16 @@
package api_test
import (
+ "net/http"
+
"github.com/odpf/stencil/server/config"
server2 "github.com/odpf/stencil/server/server"
- "github.com/gin-gonic/gin"
"github.com/odpf/stencil/server/api"
"github.com/odpf/stencil/server/api/mocks"
)
-func setup() (*gin.Engine, *mocks.StoreService, *mocks.MetadataService, *api.API) {
+func setup() (http.Handler, *mocks.StoreService, *mocks.MetadataService, *api.API) {
mockService := &mocks.StoreService{}
mockMetadataService := &mocks.MetadataService{}
v1 := &api.API{
diff --git a/server/api/download.go b/server/api/download.go
index d02e6516..9a794fdf 100644
--- a/server/api/download.go
+++ b/server/api/download.go
@@ -1,17 +1,21 @@
package api
import (
+ "context"
"fmt"
"net/http"
"net/url"
"github.com/gin-gonic/gin"
"github.com/odpf/stencil/server/models"
+ stencilv1 "github.com/odpf/stencil/server/odpf/stencil/v1"
"github.com/odpf/stencil/server/snapshot"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
)
-//Download downloads file
-func (a *API) Download(c *gin.Context) {
+//HTTPDownload http handler to download requested schema data
+func (a *API) HTTPDownload(c *gin.Context) {
ctx := c.Request.Context()
payload := models.FileDownloadRequest{
FullNames: c.QueryArray("fullnames"),
@@ -21,25 +25,44 @@ func (a *API) Download(c *gin.Context) {
return
}
s := payload.ToSnapshot()
- st, err := a.Metadata.GetSnapshot(ctx, s.Namespace, s.Name, s.Version, s.Latest)
+ data, err := a.download(ctx, s, payload.FullNames)
+ if err != nil {
+ c.Error(err)
+ return
+ }
+ fileName := payload.Version
+ c.Header("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"; filename*=UTF-8''%s`, fileName, url.PathEscape(fileName)))
+ c.Data(http.StatusOK, "application/octet-stream", data)
+}
+
+// DownloadDescriptor grpc handler to download schema data
+func (a *API) DownloadDescriptor(ctx context.Context, req *stencilv1.DownloadDescriptorRequest) (*stencilv1.DownloadDescriptorResponse, error) {
+ payload := toFileDownloadRequest(req)
+ err := validate.Struct(payload)
+ if err != nil {
+ return nil, status.Error(codes.InvalidArgument, err.Error())
+ }
+ s := payload.ToSnapshot()
+ data, err := a.download(ctx, s, req.Fullnames)
+ return &stencilv1.DownloadDescriptorResponse{Data: data}, err
+}
+
+func (a *API) download(ctx context.Context, s *snapshot.Snapshot, fullNames []string) ([]byte, error) {
+ notfoundErr := status.Error(codes.NotFound, "not found")
+ var data []byte
+ st, err := a.Metadata.GetSnapshotByFields(ctx, s.Namespace, s.Name, s.Version, s.Latest)
if err != nil {
if err == snapshot.ErrNotFound {
- c.JSON(http.StatusNotFound, gin.H{"message": err.Error()})
- return
+ return data, notfoundErr
}
- c.Error(err).SetMeta(models.ErrDownloadFailed)
- return
+ return data, status.Convert(err).Err()
}
- data, err := a.Store.Get(c.Request.Context(), st, payload.FullNames)
+ data, err = a.Store.Get(ctx, st, fullNames)
if err != nil {
- c.Error(err).SetMeta(models.ErrDownloadFailed)
- return
+ return data, status.Convert(err).Err()
}
if len(data) == 0 {
- c.JSON(http.StatusNotFound, gin.H{"message": "not found"})
- return
+ return data, notfoundErr
}
- fileName := payload.Version
- c.Header("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"; filename*=UTF-8''%s`, fileName, url.PathEscape(fileName)))
- c.Data(http.StatusOK, "application/octet-stream", data)
+ return data, nil
}
diff --git a/server/api/download_test.go b/server/api/download_test.go
index 1a32be8e..09c5acb1 100644
--- a/server/api/download_test.go
+++ b/server/api/download_test.go
@@ -1,15 +1,19 @@
package api_test
import (
+ "context"
"errors"
"fmt"
"net/http"
"net/http/httptest"
"testing"
+ "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
+ stencilv1 "github.com/odpf/stencil/server/odpf/stencil/v1"
"github.com/odpf/stencil/server/snapshot"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
+ "google.golang.org/grpc/status"
)
var downloadFail = errors.New("download fail")
@@ -31,11 +35,11 @@ func TestDownload(t *testing.T) {
{"should return 200 if download succeeded", "name1", "1.0.1", nil, nil, 200},
{"should be able to download with latest version", "name1", "latest", nil, nil, 200},
} {
- t.Run(test.desc, func(t *testing.T) {
+ t.Run(fmt.Sprintf("http: %s", test.desc), func(t *testing.T) {
router, mockService, mockMetadata, _ := setup()
fileData := []byte("File contents")
- mockMetadata.On("GetSnapshot", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&snapshot.Snapshot{}, test.notFoundErr)
+ mockMetadata.On("GetSnapshotByFields", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&snapshot.Snapshot{}, test.notFoundErr)
mockService.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(fileData, test.downloadErr)
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", fmt.Sprintf("/v1/namespaces/namespace/descriptors/%s/versions/%s", test.name, test.version), nil)
@@ -49,11 +53,27 @@ func TestDownload(t *testing.T) {
assert.Equal(t, expectedHeader, w.Header().Get("Content-Disposition"))
}
})
+ t.Run(fmt.Sprintf("gRPC: %s", test.desc), func(t *testing.T) {
+ ctx := context.Background()
+ _, mockService, mockMetadata, a := setup()
+
+ fileData := []byte("File contents")
+ mockMetadata.On("GetSnapshotByFields", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&snapshot.Snapshot{}, test.notFoundErr)
+ mockService.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(fileData, test.downloadErr)
+ req := &stencilv1.DownloadDescriptorRequest{Namespace: "namespace", Name: test.name, Version: test.version}
+ res, err := a.DownloadDescriptor(ctx, req)
+ if test.expectedCode != 200 {
+ e := status.Convert(err)
+ assert.Equal(t, test.expectedCode, runtime.HTTPStatusFromCode(e.Code()))
+ } else {
+ assert.Equal(t, res.Data, []byte("File contents"))
+ }
+ })
}
t.Run("should return 404 if file content not found", func(t *testing.T) {
router, mockService, mockMetadata, _ := setup()
fileData := []byte("")
- mockMetadata.On("GetSnapshot", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&snapshot.Snapshot{}, nil)
+ mockMetadata.On("GetSnapshotByFields", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&snapshot.Snapshot{}, nil)
mockService.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(fileData, nil)
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/v1/namespaces/namespace/descriptors/n/versions/latest", nil)
diff --git a/server/api/metadata.go b/server/api/metadata.go
index 09cadbae..2aa92c85 100644
--- a/server/api/metadata.go
+++ b/server/api/metadata.go
@@ -1,66 +1,41 @@
package api
import (
- "net/http"
+ "context"
- "github.com/gin-gonic/gin"
- "github.com/odpf/stencil/server/models"
+ stencilv1 "github.com/odpf/stencil/server/odpf/stencil/v1"
"github.com/odpf/stencil/server/snapshot"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
)
-// ListNames lists descriptor entries
-func (a *API) ListNames(c *gin.Context) {
- namespace := c.Param("namespace")
- result, err := a.Metadata.ListNames(c.Request.Context(), namespace)
+// ListSnapshots returns list of snapshots. If filters applied it will return filtered snapshot list
+func (a *API) ListSnapshots(ctx context.Context, req *stencilv1.ListSnapshotsRequest) (*stencilv1.ListSnapshotsResponse, error) {
+ res := &stencilv1.ListSnapshotsResponse{}
+ list, err := a.Metadata.List(ctx, &snapshot.Snapshot{Namespace: req.Namespace, Name: req.Name, Version: req.Version, Latest: req.Latest})
if err != nil {
- c.Error(err).SetMeta(models.ErrUnknown)
- return
+ return res, err
}
- c.JSON(http.StatusOK, result)
-}
-
-// ListVersions lists version numbers for specific name
-func (a *API) ListVersions(c *gin.Context) {
- namespace := c.Param("namespace")
- name := c.Param("name")
- result, err := a.Metadata.ListVersions(c.Request.Context(), namespace, name)
- if err != nil {
- c.Error(err).SetMeta(models.ErrUnknown)
- return
+ for _, j := range list {
+ res.Snapshots = append(res.Snapshots, fromSnapshotToProto(j))
}
- c.JSON(http.StatusOK, result)
+ return res, nil
}
-//GetLatestVersion return latest version number
-func (a *API) GetLatestVersion(c *gin.Context) {
- namespace := c.Param("namespace")
- name := c.Param("name")
- snapshot, err := a.Metadata.GetSnapshot(c.Request.Context(), namespace, name, "", true)
+// PromoteSnapshot marks specified snapshot as latest
+func (a *API) PromoteSnapshot(ctx context.Context, req *stencilv1.PromoteSnapshotRequest) (*stencilv1.PromoteSnapshotResponse, error) {
+ st, err := a.Metadata.GetSnapshotByID(ctx, req.Id)
if err != nil {
- c.Error(err).SetMeta(models.ErrGetMetadataFailed)
- return
- }
- c.JSON(http.StatusOK, gin.H{"version": snapshot.Version})
-}
-
-//UpdateLatestVersion return latest version number
-func (a *API) UpdateLatestVersion(c *gin.Context) {
- namespace := c.Param("namespace")
- payload := &models.MetadataUpdateRequest{
- Namespace: namespace,
- }
- if err := c.ShouldBind(payload); err != nil {
- c.Error(err).SetMeta(models.ErrMissingFormData)
- return
+ if err == snapshot.ErrNotFound {
+ return nil, status.Error(codes.NotFound, err.Error())
+ }
+ return nil, status.Error(codes.Internal, err.Error())
}
- err := a.Metadata.UpdateLatestVersion(c.Request.Context(), &snapshot.Snapshot{
- Namespace: namespace,
- Name: payload.Name,
- Version: payload.Version,
- })
+ err = a.Metadata.UpdateLatestVersion(ctx, st)
if err != nil {
- c.Error(err).SetMeta(models.ErrMetadataUpdateFailed)
- return
+ return nil, err
}
- c.JSON(http.StatusOK, gin.H{"message": "success"})
+ return &stencilv1.PromoteSnapshotResponse{
+ Snapshot: fromSnapshotToProto(st),
+ }, nil
}
diff --git a/server/api/metadata_test.go b/server/api/metadata_test.go
index b76c647b..2af5edcd 100644
--- a/server/api/metadata_test.go
+++ b/server/api/metadata_test.go
@@ -1,131 +1,130 @@
package api_test
import (
- "bytes"
+ "context"
"errors"
- "fmt"
- "net/http"
- "net/http/httptest"
"testing"
- "github.com/odpf/stencil/server/models"
+ stencilv1 "github.com/odpf/stencil/server/odpf/stencil/v1"
"github.com/odpf/stencil/server/snapshot"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
)
func TestList(t *testing.T) {
- for _, test := range []struct {
- desc string
- err error
- values []string
- expectedCode int
- expectedResp string
- }{
- {"should return list", nil, []string{"n1", "n2"}, 200, `["n1", "n2"]`},
- {"should return 404 if path not found", models.ErrNotFound, []string{}, 404, `{"message": "Not found"}`},
- } {
- t.Run(test.desc, func(t *testing.T) {
- router, _, mockService, _ := setup()
- mockService.On("ListNames", mock.Anything, "namespace").Return(test.values, test.err)
-
- w := httptest.NewRecorder()
- req, _ := http.NewRequest("GET", "/v1/namespaces/namespace/descriptors", nil)
- router.ServeHTTP(w, req)
-
- assert.Equal(t, test.expectedCode, w.Code)
- assert.JSONEq(t, test.expectedResp, w.Body.String())
- mockService.AssertExpectations(t)
- })
- }
-
-}
-
-func TestListVersions(t *testing.T) {
- for _, test := range []struct {
- desc string
- err error
- values []string
- expectedCode int
- expectedResp string
- }{
- {"should return list", nil, []string{"n1", "n2"}, 200, `["n1", "n2"]`},
- {"should return 404 if path not found", models.ErrNotFound, []string{}, 404, `{"message": "Not found"}`},
- } {
- t.Run(test.desc, func(t *testing.T) {
- router, _, mockService, _ := setup()
- mockService.On("ListVersions", mock.Anything, "namespace", "example").Return(test.values, test.err)
-
- w := httptest.NewRecorder()
- req, _ := http.NewRequest("GET", "/v1/namespaces/namespace/descriptors/example/versions", nil)
- router.ServeHTTP(w, req)
-
- assert.Equal(t, test.expectedCode, w.Code)
- assert.JSONEq(t, test.expectedResp, w.Body.String())
- mockService.AssertExpectations(t)
- })
- }
-}
-
-func TestGetVersion(t *testing.T) {
- for _, test := range []struct {
- desc string
- name string
- latestVersion string
- err error
- expectedCode int
- }{
- {"should return 500 if fetch version fails", "name1", "1.0.1", errors.New("fetch fail"), 500},
- {"should return latest version number", "name1", "1.0.2", nil, 200},
- } {
- t.Run(test.desc, func(t *testing.T) {
- router, _, mockService, _ := setup()
- mockService.On("GetSnapshot", mock.Anything, "namespace", test.name, "", true).Return(&snapshot.Snapshot{Version: test.latestVersion}, test.err)
- w := httptest.NewRecorder()
-
- req, _ := http.NewRequest("GET", fmt.Sprintf("/v1/namespaces/namespace/metadata/%s", test.name), nil)
-
- router.ServeHTTP(w, req)
-
- assert.Equal(t, test.expectedCode, w.Code)
- if test.expectedCode == 200 {
- expectedData := []byte(fmt.Sprintf(`{"version":"%s"}`, test.latestVersion))
- assert.Equal(t, expectedData, w.Body.Bytes())
- }
- })
- }
+ t.Run("should return list", func(t *testing.T) {
+ ctx := context.Background()
+ _, _, mockService, v1 := setup()
+ st := []*snapshot.Snapshot{
+ {
+ Namespace: "t",
+ Name: "na",
+ },
+ }
+ req := stencilv1.ListSnapshotsRequest{
+ Namespace: "t",
+ }
+ mockService.On("List", mock.Anything, &snapshot.Snapshot{Namespace: "t"}).Return(st, nil)
+ res, err := v1.ListSnapshots(ctx, &req)
+ assert.Nil(t, err)
+ assert.Equal(t, "t", res.Snapshots[0].Namespace)
+ assert.Equal(t, "na", res.Snapshots[0].Name)
+ })
+
+ t.Run("should return error if getting a list fails", func(t *testing.T) {
+ ctx := context.Background()
+ _, _, mockService, v1 := setup()
+ req := stencilv1.ListSnapshotsRequest{
+ Namespace: "t",
+ }
+ err := errors.New("list failed")
+ mockService.On("List", mock.Anything, &snapshot.Snapshot{Namespace: "t"}).Return(nil, err)
+ res, err := v1.ListSnapshots(ctx, &req)
+ assert.NotNil(t, err)
+ assert.Equal(t, 0, len(res.Snapshots))
+ })
}
func TestUpdateLatestVersion(t *testing.T) {
- for _, test := range []struct {
- desc string
- name string
- version string
- err error
- expectedCode int
- }{
- {"should return 400 if name is missing", "", "1.0.1", nil, 400},
- {"should return 400 if version is missing", "name1", "", nil, 400},
- {"should return 400 if version not follows semantic verioning", "name1", "invalid0.1.0", nil, 400},
- {"should return 500 if store fails", "name1", "1.0.1", errors.New("store fail"), 500},
- {"should return success if update succeeds", "name1", "1.0.2", nil, 200},
- } {
- t.Run(test.desc, func(t *testing.T) {
- router, _, mockService, _ := setup()
- mockService.On("UpdateLatestVersion", mock.Anything, mock.Anything).Return(test.err)
- w := httptest.NewRecorder()
-
- body := bytes.NewReader([]byte(fmt.Sprintf(`{"name": "%s", "version": "%s"}`, test.name, test.version)))
- req, _ := http.NewRequest("POST", "/v1/namespaces/namespace/metadata", body)
- req.Header.Set("Content-Type", "application/json")
-
- router.ServeHTTP(w, req)
-
- assert.Equal(t, test.expectedCode, w.Code)
- if test.expectedCode == 200 {
- assert.JSONEq(t, `{"message": "success"}`, w.Body.String())
- mockService.AssertExpectations(t)
- }
- })
- }
+ t.Run("should update latest tag", func(t *testing.T) {
+ ctx := context.Background()
+ _, _, mockService, v1 := setup()
+ st := &snapshot.Snapshot{
+ ID: 1,
+ Namespace: "t",
+ Name: "na",
+ }
+ req := &stencilv1.PromoteSnapshotRequest{
+ Id: 1,
+ }
+ mockService.On("GetSnapshotByID", mock.Anything, int64(1)).Return(st, nil)
+ mockService.On("UpdateLatestVersion", mock.Anything, st).Return(nil)
+ sp, err := v1.PromoteSnapshot(ctx, req)
+ res := sp.Snapshot
+ assert.Nil(t, err)
+ assert.Equal(t, int64(1), res.Id)
+ assert.Equal(t, "t", res.Namespace)
+ assert.Equal(t, "na", res.Name)
+ })
+ t.Run("should return not found err if snapshot not found", func(t *testing.T) {
+ ctx := context.Background()
+ _, _, mockService, v1 := setup()
+ st := &snapshot.Snapshot{
+ ID: 1,
+ Namespace: "t",
+ Name: "na",
+ }
+ req := &stencilv1.PromoteSnapshotRequest{
+ Id: 1,
+ }
+ mockService.On("GetSnapshotByID", mock.Anything, int64(1)).Return(st, snapshot.ErrNotFound)
+ mockService.On("UpdateLatestVersion", mock.Anything, st).Return(nil)
+ _, err := v1.PromoteSnapshot(ctx, req)
+ assert.NotNil(t, err)
+ s := status.Convert(err)
+ assert.Equal(t, codes.NotFound.String(), s.Code().String())
+ assert.Equal(t, "not found", s.Message())
+ })
+ t.Run("should mark as internal error if get snapshot fails", func(t *testing.T) {
+ ctx := context.Background()
+ _, _, mockService, v1 := setup()
+ st := &snapshot.Snapshot{
+ ID: 1,
+ Namespace: "t",
+ Name: "na",
+ }
+ req := &stencilv1.PromoteSnapshotRequest{
+ Id: 1,
+ }
+ err := errors.New("internal")
+ mockService.On("GetSnapshotByID", mock.Anything, int64(1)).Return(st, err)
+ mockService.On("UpdateLatestVersion", mock.Anything, st).Return(nil)
+ _, err = v1.PromoteSnapshot(ctx, req)
+ assert.NotNil(t, err)
+ s := status.Convert(err)
+ assert.Equal(t, codes.Internal.String(), s.Code().String())
+ assert.Equal(t, "internal", s.Message())
+ })
+ t.Run("should mark as internal error if update snapshot fails", func(t *testing.T) {
+ ctx := context.Background()
+ _, _, mockService, v1 := setup()
+ st := &snapshot.Snapshot{
+ ID: 1,
+ Namespace: "t",
+ Name: "na",
+ }
+ req := &stencilv1.PromoteSnapshotRequest{
+ Id: 1,
+ }
+ err := errors.New("internal")
+ mockService.On("GetSnapshotByID", mock.Anything, int64(1)).Return(st, nil)
+ mockService.On("UpdateLatestVersion", mock.Anything, st).Return(err)
+ _, err = v1.PromoteSnapshot(ctx, req)
+ assert.NotNil(t, err)
+ s := status.Convert(err)
+ assert.Equal(t, codes.Unknown.String(), s.Code().String())
+ assert.Equal(t, "internal", s.Message())
+ })
}
diff --git a/server/api/mocks/MetadataService.go b/server/api/mocks/MetadataService.go
index 9b6fb121..c7e0fb15 100644
--- a/server/api/mocks/MetadataService.go
+++ b/server/api/mocks/MetadataService.go
@@ -28,8 +28,8 @@ func (_m *MetadataService) Exists(_a0 context.Context, _a1 *snapshot.Snapshot) b
return r0
}
-// GetSnapshot provides a mock function with given fields: _a0, _a1, _a2, _a3, _a4
-func (_m *MetadataService) GetSnapshot(_a0 context.Context, _a1 string, _a2 string, _a3 string, _a4 bool) (*snapshot.Snapshot, error) {
+// GetSnapshotByFields provides a mock function with given fields: _a0, _a1, _a2, _a3, _a4
+func (_m *MetadataService) GetSnapshotByFields(_a0 context.Context, _a1 string, _a2 string, _a3 string, _a4 bool) (*snapshot.Snapshot, error) {
ret := _m.Called(_a0, _a1, _a2, _a3, _a4)
var r0 *snapshot.Snapshot
@@ -51,21 +51,21 @@ func (_m *MetadataService) GetSnapshot(_a0 context.Context, _a1 string, _a2 stri
return r0, r1
}
-// ListNames provides a mock function with given fields: _a0, _a1
-func (_m *MetadataService) ListNames(_a0 context.Context, _a1 string) ([]string, error) {
+// GetSnapshotByID provides a mock function with given fields: _a0, _a1
+func (_m *MetadataService) GetSnapshotByID(_a0 context.Context, _a1 int64) (*snapshot.Snapshot, error) {
ret := _m.Called(_a0, _a1)
- var r0 []string
- if rf, ok := ret.Get(0).(func(context.Context, string) []string); ok {
+ var r0 *snapshot.Snapshot
+ if rf, ok := ret.Get(0).(func(context.Context, int64) *snapshot.Snapshot); ok {
r0 = rf(_a0, _a1)
} else {
if ret.Get(0) != nil {
- r0 = ret.Get(0).([]string)
+ r0 = ret.Get(0).(*snapshot.Snapshot)
}
}
var r1 error
- if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
+ if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
r1 = rf(_a0, _a1)
} else {
r1 = ret.Error(1)
@@ -74,22 +74,22 @@ func (_m *MetadataService) ListNames(_a0 context.Context, _a1 string) ([]string,
return r0, r1
}
-// ListVersions provides a mock function with given fields: _a0, _a1, _a2
-func (_m *MetadataService) ListVersions(_a0 context.Context, _a1 string, _a2 string) ([]string, error) {
- ret := _m.Called(_a0, _a1, _a2)
+// List provides a mock function with given fields: _a0, _a1
+func (_m *MetadataService) List(_a0 context.Context, _a1 *snapshot.Snapshot) ([]*snapshot.Snapshot, error) {
+ ret := _m.Called(_a0, _a1)
- var r0 []string
- if rf, ok := ret.Get(0).(func(context.Context, string, string) []string); ok {
- r0 = rf(_a0, _a1, _a2)
+ var r0 []*snapshot.Snapshot
+ if rf, ok := ret.Get(0).(func(context.Context, *snapshot.Snapshot) []*snapshot.Snapshot); ok {
+ r0 = rf(_a0, _a1)
} else {
if ret.Get(0) != nil {
- r0 = ret.Get(0).([]string)
+ r0 = ret.Get(0).([]*snapshot.Snapshot)
}
}
var r1 error
- if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
- r1 = rf(_a0, _a1, _a2)
+ if rf, ok := ret.Get(1).(func(context.Context, *snapshot.Snapshot) error); ok {
+ r1 = rf(_a0, _a1)
} else {
r1 = ret.Error(1)
}
diff --git a/server/api/noroute.go b/server/api/noroute.go
deleted file mode 100644
index e5ccc6b5..00000000
--- a/server/api/noroute.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package api
-
-import (
- "github.com/gin-gonic/gin"
-)
-
-//NoRoute default response for no route
-func NoRoute(c *gin.Context) {
- c.JSON(404, gin.H{"message": "page not found"})
-}
diff --git a/server/api/noroute_test.go b/server/api/noroute_test.go
deleted file mode 100644
index 152dc9a7..00000000
--- a/server/api/noroute_test.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package api_test
-
-import (
- "net/http"
- "net/http/httptest"
- "testing"
-
- "github.com/odpf/stencil/server/config"
- server2 "github.com/odpf/stencil/server/server"
-
- "github.com/odpf/stencil/server/api"
- "github.com/stretchr/testify/assert"
-)
-
-func TestNoRoute(t *testing.T) {
- router := server2.Router(&api.API{}, &config.Config{})
- w := httptest.NewRecorder()
- req, _ := http.NewRequest("GET", "/random", nil)
- router.ServeHTTP(w, req)
-
- assert.Equal(t, 404, w.Code)
- assert.JSONEq(t, `{"message": "page not found"}`, w.Body.String())
-}
diff --git a/server/api/ping.go b/server/api/ping.go
index b5fb93e6..da8f179a 100644
--- a/server/api/ping.go
+++ b/server/api/ping.go
@@ -1,10 +1,18 @@
package api
import (
+ "context"
+
"github.com/gin-gonic/gin"
+ "google.golang.org/grpc/health/grpc_health_v1"
)
//Ping handler
func Ping(c *gin.Context) {
c.JSON(200, gin.H{"message": "pong"})
}
+
+//Check grpc health check
+func (s *API) Check(ctx context.Context, in *grpc_health_v1.HealthCheckRequest) (*grpc_health_v1.HealthCheckResponse, error) {
+ return &grpc_health_v1.HealthCheckResponse{Status: grpc_health_v1.HealthCheckResponse_SERVING}, nil
+}
diff --git a/server/api/upload.go b/server/api/upload.go
index 0ed98dd7..0190e094 100644
--- a/server/api/upload.go
+++ b/server/api/upload.go
@@ -1,6 +1,7 @@
package api
import (
+ "context"
"io"
"io/ioutil"
"mime/multipart"
@@ -8,10 +9,14 @@ import (
"github.com/gin-gonic/gin"
"github.com/odpf/stencil/server/models"
+ stencilv1 "github.com/odpf/stencil/server/odpf/stencil/v1"
+ "github.com/odpf/stencil/server/snapshot"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
)
-//Upload uploads file
-func (a *API) Upload(c *gin.Context) {
+// HTTPUpload http handler to schema data with metadata information
+func (a *API) HTTPUpload(c *gin.Context) {
ctx := c.Request.Context()
namespace := c.Param("namespace")
payload := &models.DescriptorUploadRequest{
@@ -27,25 +32,49 @@ func (a *API) Upload(c *gin.Context) {
return
}
currentSnapshot := payload.ToSnapshot()
- if ok := a.Metadata.Exists(ctx, currentSnapshot); ok {
- c.JSON(http.StatusConflict, gin.H{"message": "Resource already exist"})
+ err = a.upload(ctx, currentSnapshot, data, payload.SkipRules, payload.DryRun)
+ if err != nil {
+ c.Error(err)
return
}
- err = a.Store.Validate(ctx, currentSnapshot, data, payload.SkipRules)
+ c.JSON(http.StatusOK, gin.H{"message": "success", "dryrun": payload.DryRun})
+}
+
+// UploadDescriptor grpc handler to upload schema data with metadata information
+func (a *API) UploadDescriptor(ctx context.Context, req *stencilv1.UploadDescriptorRequest) (*stencilv1.UploadDescriptorResponse, error) {
+ res := &stencilv1.UploadDescriptorResponse{
+ Dryrun: req.Dryrun,
+ }
+ s := fromProtoToSnapshot(&stencilv1.Snapshot{Namespace: req.Namespace, Name: req.Name, Version: req.Version, Latest: req.Latest})
+ err := validate.StructExcept(s, "ID", "Latest")
if err != nil {
- c.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
- return
+ res.Errors = err.Error()
+ return res, status.Error(codes.InvalidArgument, err.Error())
}
- if payload.DryRun {
- c.JSON(http.StatusOK, gin.H{"message": "success", "dryrun": "true"})
- return
+ if err := a.upload(ctx, s, req.Data, toRulesList(req.Checks), req.Dryrun); err != nil {
+ res.Errors = err.Error()
+ return res, err
}
- err = a.Store.Insert(ctx, currentSnapshot, data)
+ res.Success = true
+ return res, nil
+}
+
+func (a *API) upload(ctx context.Context, snapshot *snapshot.Snapshot, data []byte, skipRules []string, dryrun bool) error {
+ if ok := a.Metadata.Exists(ctx, snapshot); ok {
+ return status.Error(codes.AlreadyExists, "Resource already exists")
+ }
+ err := a.Store.Validate(ctx, snapshot, data, skipRules)
if err != nil {
- c.Error(err).SetMeta(models.ErrUploadFailed)
- return
+ return status.Error(codes.InvalidArgument, err.Error())
+ }
+ if dryrun {
+ return nil
+ }
+ err = a.Store.Insert(ctx, snapshot, data)
+ if err != nil {
+ return status.Error(codes.Internal, err.Error())
}
- c.JSON(http.StatusOK, gin.H{"message": "success"})
+ return nil
}
func readDataFromReader(reader io.ReadCloser) ([]byte, error) {
diff --git a/server/api/upload_test.go b/server/api/upload_test.go
index 480420fe..9ad486af 100644
--- a/server/api/upload_test.go
+++ b/server/api/upload_test.go
@@ -2,6 +2,7 @@ package api_test
import (
"bytes"
+ "context"
"errors"
"fmt"
"io"
@@ -12,9 +13,12 @@ import (
"strconv"
"testing"
+ "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/odpf/stencil/server/models"
+ stencilv1 "github.com/odpf/stencil/server/odpf/stencil/v1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
+ "google.golang.org/grpc/status"
)
var (
@@ -64,8 +68,8 @@ func TestUpload(t *testing.T) {
{"should return 400 if version is missing", "name1", "", false, nil, nil, 400, formError},
{"should return 400 if version is invalid semantic version", "name1", "invalid", false, nil, nil, 400, formError},
{"should return 400 if backward check fails", "name1", "1.0.1", false, errors.New("validation"), nil, 400, "validation"},
- {"should return 409 if resource already exists", "name1", "1.0.1", true, nil, nil, 409, "Resource already exist"},
- {"should return 500 if insert fails", "name1", "1.0.1", false, nil, errors.New("insert fail"), 500, uploadError},
+ {"should return 409 if resource already exists", "name1", "1.0.1", true, nil, nil, 409, "Resource already exists"},
+ {"should return 500 if insert fails", "name1", "1.0.1", false, nil, errors.New("insert fail"), 500, "Internal error"},
{"should return 200 if upload succeeded", "name1", "1.0.1", false, nil, nil, 200, success},
} {
t.Run(test.desc, func(t *testing.T) {
@@ -81,7 +85,33 @@ func TestUpload(t *testing.T) {
router.ServeHTTP(w, req)
assert.Equal(t, test.expectedCode, w.Code)
- assert.JSONEq(t, fmt.Sprintf(`{"message": "%s"}`, test.responseMsg), w.Body.String())
+
+ if w.Code == 200 {
+ assert.JSONEq(t, fmt.Sprintf(`{"message": "%s", "dryrun": false}`, test.responseMsg), w.Body.String())
+ } else {
+ assert.JSONEq(t, fmt.Sprintf(`{"message": "%s"}`, test.responseMsg), w.Body.String())
+ }
+ })
+ t.Run(fmt.Sprintf("gRPC: %s", test.desc), func(t *testing.T) {
+ _, mockService, metadata, api := setup()
+ metadata.On("Exists", mock.Anything, mock.Anything).Return(test.exists)
+ mockService.On("Validate", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(test.validateErr)
+ mockService.On("Insert", mock.Anything, mock.Anything, mock.Anything).Return(test.insertErr)
+ data, err := os.ReadFile("./testdata/test.desc")
+ assert.Nil(t, err)
+ req := &stencilv1.UploadDescriptorRequest{
+ Namespace: "namespace", Name: test.name, Version: test.version,
+ Data: data,
+ }
+ res, err := api.UploadDescriptor(context.Background(), req)
+ if test.expectedCode != 200 {
+ e := status.Convert(err)
+ assert.Equal(t, test.expectedCode, runtime.HTTPStatusFromCode(e.Code()))
+ } else {
+ assert.Equal(t, res.Dryrun, false)
+ assert.Equal(t, res.Success, true)
+ assert.Equal(t, res.Errors, "")
+ }
})
}
@@ -100,7 +130,7 @@ func TestUpload(t *testing.T) {
router.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
- assert.JSONEq(t, `{"message": "success", "dryrun": "true"}`, w.Body.String())
+ assert.JSONEq(t, `{"message": "success", "dryrun": true}`, w.Body.String())
mockService.AssertNotCalled(t, "Insert", mock.Anything, mock.Anything, mock.Anything)
})
}
diff --git a/server/api/validator.go b/server/api/validator.go
new file mode 100644
index 00000000..3f27e922
--- /dev/null
+++ b/server/api/validator.go
@@ -0,0 +1,23 @@
+package api
+
+import (
+ "github.com/blang/semver/v4"
+ v "github.com/go-playground/validator/v10"
+)
+
+var validate *v.Validate
+
+func init() {
+ validate = v.New()
+ validate.SetTagName("binding")
+ validate.RegisterValidation("version", func(fl v.FieldLevel) bool {
+ version, ok := fl.Field().Interface().(string)
+ if ok {
+ if _, err := semver.Parse(version); err == nil {
+ return true
+ }
+ return false
+ }
+ return false
+ })
+}
diff --git a/server/cmd/upload.go b/server/cmd/upload.go
new file mode 100644
index 00000000..79a1fa08
--- /dev/null
+++ b/server/cmd/upload.go
@@ -0,0 +1,60 @@
+package cmd
+
+import (
+ "context"
+ "io/ioutil"
+ "log"
+
+ stencilv1 "github.com/odpf/stencil/server/odpf/stencil/v1"
+ "github.com/spf13/cobra"
+ "google.golang.org/grpc"
+)
+
+var host, namespace, name, version, filePath string
+var latest bool
+
+func init() {
+ uploadCmd := &cobra.Command{
+ Use: "upload",
+ Short: "Upload filedescriptorset file",
+ Run: upload,
+ Args: cobra.NoArgs,
+ }
+ uploadCmd.Flags().StringVarP(&host, "host", "h", "", "stencil host address eg: localhost:8000")
+ uploadCmd.MarkFlagRequired("host")
+ uploadCmd.Flags().StringVarP(&namespace, "namespace", "g", "", "provide namespace/group or entity name")
+ uploadCmd.MarkFlagRequired("namespace")
+ uploadCmd.Flags().StringVarP(&name, "name", "n", "", "provide proto repo name")
+ uploadCmd.MarkFlagRequired("name")
+ uploadCmd.Flags().StringVarP(&version, "version", "v", "", "provide semantic version compatible value")
+ uploadCmd.MarkFlagRequired("version")
+ uploadCmd.Flags().BoolVarP(&latest, "latest", "l", false, "mark as latest version")
+ uploadCmd.Flags().StringVarP(&filePath, "file", "f", "", "provide path to fully contained file descriptor set file")
+ uploadCmd.MarkFlagRequired("file")
+ rootCmd.AddCommand(uploadCmd)
+}
+
+func upload(cmd *cobra.Command, args []string) {
+ fileData, err := ioutil.ReadFile(filePath)
+ if err != nil {
+ log.Fatalln("Unable to read provided file", err)
+ }
+ conn, err := grpc.Dial(host, grpc.WithInsecure())
+ if err != nil {
+ log.Fatalln(err)
+ }
+ defer conn.Close()
+ client := stencilv1.NewStencilServiceClient(conn)
+ ur := &stencilv1.UploadDescriptorRequest{
+ Namespace: namespace,
+ Name: name,
+ Version: version,
+ Latest: latest,
+ Data: fileData,
+ }
+ res, err := client.UploadDescriptor(context.Background(), ur)
+ if err != nil {
+ log.Fatalln(err)
+ }
+ log.Println(res)
+}
diff --git a/server/config/config.go b/server/config/config.go
index cf0a852e..26262393 100644
--- a/server/config/config.go
+++ b/server/config/config.go
@@ -24,12 +24,19 @@ type DBConfig struct {
MigrationsPath string
}
+//GRPCConfig grpc options
+type GRPCConfig struct {
+ MaxRecvMsgSizeInMB int `default:"10"`
+ MaxSendMsgSizeInMB int `default:"10"`
+}
+
//Config Server config
type Config struct {
Port string `default:"8080"`
//Timeout represents graceful shutdown period.
//Default is 60 seconds.
Timeout time.Duration `default:"60s"`
+ GRPC GRPCConfig
NewRelic NewRelicConfig
DB DBConfig
}
diff --git a/server/docs/api.md b/server/docs/api.md
index 5d0b0ac0..5ff55b48 100644
--- a/server/docs/api.md
+++ b/server/docs/api.md
@@ -2,7 +2,7 @@
> Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.
-
Default
+health
## ping
@@ -30,9 +30,7 @@ curl -X GET /ping
This operation does not require authentication
-descriptors
-
-Manage descriptors
+StencilService
## post__v1_namespaces_{namespace}_descriptors
@@ -88,232 +86,248 @@ file: string
|Status|Meaning|Description|Schema|
|---|---|---|---|
-|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Success response|None|
-|409|[Conflict](https://tools.ietf.org/html/rfc7231#section-6.5.8)|Conflict|None|
+|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Success response if operation succeded|None|
+|400|[Bad Request](https://tools.ietf.org/html/rfc7231#section-6.5.1)|Validation error response when user payload has missing required fields or currently being uploaded file is not backward compatible with previously uploaded file|None|
+|409|[Conflict](https://tools.ietf.org/html/rfc7231#section-6.5.8)|conflict error reponse if namespace, name and version combination already present|None|
+|500|[Internal Server Error](https://tools.ietf.org/html/rfc7231#section-6.6.1)|Unexpected internal error reponse|None|
This operation does not require authentication
-## get__v1_namespaces_{namespace}_descriptors
+## get__v1_namespaces_{namespace}_descriptors_{name}_versions_{version}
> Code samples
```shell
# You can also use wget
-curl -X GET /v1/namespaces/{namespace}/descriptors \
- -H 'Accept: application/json'
+curl -X GET /v1/namespaces/{namespace}/descriptors/{name}/versions/{version}
```
-`GET /v1/namespaces/{namespace}/descriptors`
+`GET /v1/namespaces/{namespace}/descriptors/{name}/versions/{version}`
-*list all available descriptor names under one namespace*
+*download specified descriptor file*
-Parameters
+Parameters
|Name|In|Type|Required|Description|
|---|---|---|---|---|
|namespace|path|string|true|none|
+|name|path|string|true|none|
+|version|path|string|true|none|
+|fullnames|query|array[string]|false|Proto fullnames|
-> Example responses
-
-> 200 Response
-
-```json
-[
- "string"
-]
-```
-
-Responses
+Responses
|Status|Meaning|Description|Schema|
|---|---|---|---|
-|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|returns list of descriptor names|Inline|
-
-Response Schema
+|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|download response|None|
This operation does not require authentication
-## get__v1_namespaces_{namespace}_descriptors_{name}_versions
+## StencilService_ListSnapshots
+
+
> Code samples
```shell
# You can also use wget
-curl -X GET /v1/namespaces/{namespace}/descriptors/{name}/versions \
+curl -X GET /v1/snapshots \
-H 'Accept: application/json'
```
-`GET /v1/namespaces/{namespace}/descriptors/{name}/versions`
-
-*list all available versions for specified descriptor*
+`GET /v1/snapshots`
-Parameters
+Parameters
|Name|In|Type|Required|Description|
|---|---|---|---|---|
-|namespace|path|string|true|none|
-|name|path|string|true|none|
+|namespace|query|string|false|none|
+|name|query|string|false|none|
+|version|query|string|false|none|
+|latest|query|boolean|false|none|
> Example responses
> 200 Response
```json
-[
- "string"
-]
+{
+ "snapshots": [
+ {
+ "id": "string",
+ "namespace": "string",
+ "name": "string",
+ "version": "string",
+ "latest": true
+ }
+ ]
+}
```
-Responses
+Responses
|Status|Meaning|Description|Schema|
|---|---|---|---|
-|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|returns list of versions|Inline|
-
-Response Schema
+|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|A successful response.|[v1ListSnapshotsResponse](#schemav1listsnapshotsresponse)|
+|default|Default|An unexpected error response.|[rpcStatus](#schemarpcstatus)|
This operation does not require authentication
-## get__v1_namespaces_{namespace}_descriptors_{name}_versions_{version}
+## StencilService_PromoteSnapshot
+
+
> Code samples
```shell
# You can also use wget
-curl -X GET /v1/namespaces/{namespace}/descriptors/{name}/versions/{version}
+curl -X PATCH /v1/snapshots/{id}/promote \
+ -H 'Accept: application/json'
```
-`GET /v1/namespaces/{namespace}/descriptors/{name}/versions/{version}`
+`PATCH /v1/snapshots/{id}/promote`
-*download specified descriptor file*
+*PromoteSnapshot promotes particular snapshot version as latest*
-Parameters
+
|Name|In|Type|Required|Description|
|---|---|---|---|---|
-|namespace|path|string|true|none|
-|name|path|string|true|none|
-|version|path|string|true|none|
-|fullnames|query|array[string]|false|Proto fullnames|
-
-Responses
-
-|Status|Meaning|Description|Schema|
-|---|---|---|---|
-|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|download response|None|
-
-
-This operation does not require authentication
-
-
-
-
-manage latest versions for uploaded descriptor files
+|id|path|string(int64)|true|none|
-## post__v1_namespaces_{namespace}_metadata
-
-> Code samples
-
-```shell
-# You can also use wget
-curl -X POST /v1/namespaces/{namespace}/metadata \
- -H 'Content-Type: application/json'
-
-```
-
-`POST /v1/namespaces/{namespace}/metadata`
-
-*update metadata*
+> Example responses
-> Body parameter
+> 200 Response
```json
{
- "name": "string",
- "version": "string"
+ "snapshot": {
+ "id": "string",
+ "namespace": "string",
+ "name": "string",
+ "version": "string",
+ "latest": true
+ }
}
```
-Parameters
-
-|Name|In|Type|Required|Description|
-|---|---|---|---|---|
-|namespace|path|string|true|none|
-|body|body|[MetadataPayload](#schemametadatapayload)|true|specify name and version in payload|
-
-Responses
+
|Status|Meaning|Description|Schema|
|---|---|---|---|
-|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Success response|None|
+|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|A successful response.|[v1PromoteSnapshotResponse](#schemav1promotesnapshotresponse)|
+|default|Default|An unexpected error response.|[rpcStatus](#schemarpcstatus)|
This operation does not require authentication
-## get__v1_namespaces_{namespace}_metadata_{name}
+# Schemas
-> Code samples
+protobufAny
+
+
+
+
+
-```shell
-# You can also use wget
-curl -X GET /v1/namespaces/{namespace}/metadata/{name} \
- -H 'Accept: application/json'
+```json
+{
+ "typeUrl": "string",
+ "value": "string"
+}
```
-`GET /v1/namespaces/{namespace}/metadata/{name}`
-
-*get latest version for specified descriptor*
-
-
+### Properties
-|Name|In|Type|Required|Description|
+|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
-|namespace|path|string|true|none|
-|name|path|string|true|none|
-
-> Example responses
+|typeUrl|string|false|none|none|
+|value|string(byte)|false|none|none|
-> 200 Response
+rpcStatus
+
+
+
+
+
```json
{
- "version": "string"
+ "code": 0,
+ "message": "string",
+ "details": [
+ {
+ "typeUrl": "string",
+ "value": "string"
+ }
+ ]
}
+
```
-
+### Properties
-|Status|Meaning|Description|Schema|
-|---|---|---|---|
-|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Success response|[MetadataResponse](#schemametadataresponse)|
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|code|integer(int32)|false|none|none|
+|message|string|false|none|none|
+|details|[[protobufAny](#schemaprotobufany)]|false|none|none|
-
-This operation does not require authentication
-
+v1ListSnapshotsResponse
+
+
+
+
+
-# Schemas
+```json
+{
+ "snapshots": [
+ {
+ "id": "string",
+ "namespace": "string",
+ "name": "string",
+ "version": "string",
+ "latest": true
+ }
+ ]
+}
+
+```
+
+### Properties
-
+|Name|Type|Required|Restrictions|Description|
+|---|---|---|---|---|
+|snapshots|[[v1Snapshot](#schemav1snapshot)]|false|none|none|
+
+
-
-
-
-
+
+
+
+
```json
{
- "version": "string"
+ "snapshot": {
+ "id": "string",
+ "namespace": "string",
+ "name": "string",
+ "version": "string",
+ "latest": true
+ }
}
```
@@ -322,19 +336,22 @@ This operation does not require authentication
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
-|version|string|false|none|none|
+|snapshot|[v1Snapshot](#schemav1snapshot)|false|none|none|
-
+v1Snapshot
-
-
-
-
+
+
+
+
```json
{
+ "id": "string",
+ "namespace": "string",
"name": "string",
- "version": "string"
+ "version": "string",
+ "latest": true
}
```
@@ -343,9 +360,9 @@ This operation does not require authentication
|Name|Type|Required|Restrictions|Description|
|---|---|---|---|---|
+|id|string(int64)|false|none|none|
+|namespace|string|true|none|none|
|name|string|false|none|none|
|version|string|false|none|none|
-
-
-
+|latest|boolean|false|none|none|
diff --git a/server/go.mod b/server/go.mod
index e22fa6b0..6d528379 100644
--- a/server/go.mod
+++ b/server/go.mod
@@ -8,16 +8,24 @@ require (
github.com/gin-gonic/gin v1.7.4
github.com/go-playground/validator/v10 v10.4.1
github.com/golang-migrate/migrate/v4 v4.14.1
+ github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0
github.com/jackc/pgx/v4 v4.13.0
github.com/jeremywohl/flatten v1.0.1
github.com/mcuadros/go-defaults v1.2.0
github.com/mitchellh/mapstructure v1.4.1
github.com/newrelic/go-agent/v3 v3.12.0
github.com/newrelic/go-agent/v3/integrations/nrgin v1.1.0
+ github.com/newrelic/go-agent/v3/integrations/nrgrpc v1.3.1
github.com/spf13/cobra v1.2.1
github.com/spf13/viper v1.8.1
github.com/stretchr/testify v1.7.0
go.uber.org/multierr v1.6.0
go.uber.org/zap v1.19.0
- google.golang.org/protobuf v1.26.0
+ golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
+ golang.org/x/sys v0.0.0-20210819072135-bce67f096156 // indirect
+ golang.org/x/text v0.3.7 // indirect
+ google.golang.org/genproto v0.0.0-20210818220304-27ea9cc85d9f
+ google.golang.org/grpc v1.40.0
+ google.golang.org/protobuf v1.27.1
)
diff --git a/server/go.sum b/server/go.sum
index f9dbbd4d..b4573c16 100644
--- a/server/go.sum
+++ b/server/go.sum
@@ -48,6 +48,7 @@ github.com/ClickHouse/clickhouse-go v1.3.12/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhH
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apache/arrow/go/arrow v0.0.0-20200601151325-b2287a20f230/go.mod h1:QNYViu/X0HXDHw7m3KXzWSVXIbfUvJqBFe6Gj8/pYA0=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@@ -65,6 +66,7 @@ github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2y
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -73,6 +75,7 @@ github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/cockroach-go v0.0.0-20190925194419-606b3d062051 h1:eApuUG8W2EtBVwxqLlY2wgoqDYOg3WvIHGvW4fUbbow=
@@ -112,6 +115,7 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
@@ -131,7 +135,9 @@ github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjX
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
@@ -158,6 +164,8 @@ github.com/golang-migrate/migrate/v4 v4.14.1 h1:qmRd/rNGjM1r3Ve5gHd5ZplytrD02UcI
github.com/golang-migrate/migrate/v4 v4.14.1/go.mod h1:l7Ks0Au6fYHuUIxUhQ0rcVX1uLlJg54C/VvW7tvxSz0=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/glog v0.0.0-20210429001901-424d2337a529 h1:2voWjNECnrZRbfwXxHB1/j8wa6xdKn85B5NzgVL/pTU=
+github.com/golang/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -203,8 +211,9 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -234,7 +243,12 @@ github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
+github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
+github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0 h1:ajue7SzQMywqRjg2fK7dcpc0QhFGpTR2plWfV4EZWR4=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0/go.mod h1:r1hZAcvfFXuYmcKyCJI9wlyOPIZUJl6FCB8Cpca/NLE=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
@@ -363,6 +377,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
@@ -426,6 +441,8 @@ github.com/newrelic/go-agent/v3 v3.12.0 h1:tcDo0Q8qRWAJqb9uykfmM8pxGSbv0HqSS3q1+
github.com/newrelic/go-agent/v3 v3.12.0/go.mod h1:1A1dssWBwzB7UemzRU6ZVaGDsI+cEn5/bNxI0wiYlIc=
github.com/newrelic/go-agent/v3/integrations/nrgin v1.1.0 h1:lbxcXUImLm7FEvjwDll3jnZ3P+AyZo9gN5UVNg6NYNM=
github.com/newrelic/go-agent/v3/integrations/nrgin v1.1.0/go.mod h1:CYFq0517T2EwtONPFd+7qFsrpSR0nydqQf22N284nok=
+github.com/newrelic/go-agent/v3/integrations/nrgrpc v1.3.1 h1:/ar1Omo9luapTJYWXt86oQGBpWwpWF92x+UuYU9v/7o=
+github.com/newrelic/go-agent/v3/integrations/nrgrpc v1.3.1/go.mod h1:2q0u6qkNJ4ClDt920A4r+NpcO370lFze1NF4OPJjAks=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -436,6 +453,7 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
@@ -476,6 +494,7 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/snowflakedb/glog v0.0.0-20180824191149-f5055e6f21ce/go.mod h1:EB/w24pR5VKI60ecFnKqXzxX3dOorz1rnVicQTQrGM0=
github.com/snowflakedb/gosnowflake v1.3.5/go.mod h1:13Ky+lxzIm3VqNDZJdyvu9MCGy+WgRdYFdXp96UcLZU=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
@@ -529,6 +548,7 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@@ -646,8 +666,9 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
-golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c=
+golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -662,6 +683,7 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -727,9 +749,11 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210819072135-bce67f096156 h1:f7XLk/QXGE6IM4HjJ4ttFFlPSwJ65A1apfDd+mmViR0=
+golang.org/x/sys v0.0.0-20210819072135-bce67f096156/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -739,8 +763,9 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -806,8 +831,10 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
-golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
+golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -867,6 +894,7 @@ google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
@@ -890,8 +918,10 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
-google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
+google.golang.org/genproto v0.0.0-20210818220304-27ea9cc85d9f h1:enWPderunHptc5pzJkSYGx0olpF8goXzG0rY3kL0eSg=
+google.golang.org/genproto v0.0.0-20210818220304-27ea9cc85d9f/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -912,8 +942,9 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=
+google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -925,8 +956,9 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
+google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
diff --git a/server/logger/logger.go b/server/logger/logger.go
new file mode 100644
index 00000000..8b013f72
--- /dev/null
+++ b/server/logger/logger.go
@@ -0,0 +1,18 @@
+package logger
+
+import (
+ "log"
+
+ "go.uber.org/zap"
+)
+
+// Logger zap logger instance
+var Logger *zap.Logger
+
+func init() {
+ l, err := zap.NewProduction()
+ if err != nil {
+ log.Fatalln(err)
+ }
+ Logger = l
+}
diff --git a/server/main.go b/server/main.go
index 799edfbd..9c491fbb 100644
--- a/server/main.go
+++ b/server/main.go
@@ -1,6 +1,8 @@
package main
-import "github.com/odpf/stencil/server/cmd"
+import (
+ "github.com/odpf/stencil/server/cmd"
+)
func main() {
cmd.Execute()
diff --git a/server/models/descriptor.go b/server/models/descriptor.go
index 1aa396d0..592cdae8 100644
--- a/server/models/descriptor.go
+++ b/server/models/descriptor.go
@@ -9,7 +9,7 @@ import (
type FileDownloadRequest struct {
Namespace string `uri:"namespace" binding:"required"`
Name string `uri:"name" binding:"required"`
- Version string `uri:"version" binding:"required,versionWithLatest"`
+ Version string `uri:"version" binding:"required,version|eq=latest"`
FullNames []string
}
@@ -46,18 +46,3 @@ func (d *DescriptorUploadRequest) ToSnapshot() *snapshot.Snapshot {
Latest: d.Latest,
}
}
-
-type GetMetadataRequest struct {
- Namespace string `uri:"namespace" binding:"required"`
- Name string `uri:"name" binding:"required"`
-}
-
-type MetadataUpdateRequest struct {
- Namespace string
- Name string `json:"name" binding:"required"`
- Version string `json:"version" binding:"required,version"`
-}
-
-type MetadataFile struct {
- Version string `json:"version"`
-}
diff --git a/server/models/error.go b/server/models/error.go
index 2b82b27c..b497e640 100644
--- a/server/models/error.go
+++ b/server/models/error.go
@@ -86,6 +86,9 @@ func (a *apiErr) Error() string {
if err == nil {
err = errors.New("")
}
+ if a.code >= 500 {
+ return a.message
+ }
return fmt.Sprintf("Err: %s, Message: %s", err.Error(), a.Message())
}
diff --git a/server/odpf/stencil/v1/stencil.pb.go b/server/odpf/stencil/v1/stencil.pb.go
new file mode 100644
index 00000000..a3fc78e2
--- /dev/null
+++ b/server/odpf/stencil/v1/stencil.pb.go
@@ -0,0 +1,1021 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.27.1
+// protoc v3.17.3
+// source: odpf/stencil/v1/stencil.proto
+
+package stencilv1
+
+import (
+ _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options"
+ _ "google.golang.org/genproto/googleapis/api/annotations"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ _ "google.golang.org/protobuf/types/descriptorpb"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Rule int32
+
+const (
+ Rule_UNKNOWN Rule = 0
+ Rule_FILE_NO_BREAKING_CHANGE Rule = 1
+ Rule_MESSAGE_NO_DELETE Rule = 2
+ Rule_FIELD_NO_BREAKING_CHANGE Rule = 3
+ Rule_ENUM_NO_BREAKING_CHANGE Rule = 4
+)
+
+// Enum value maps for Rule.
+var (
+ Rule_name = map[int32]string{
+ 0: "UNKNOWN",
+ 1: "FILE_NO_BREAKING_CHANGE",
+ 2: "MESSAGE_NO_DELETE",
+ 3: "FIELD_NO_BREAKING_CHANGE",
+ 4: "ENUM_NO_BREAKING_CHANGE",
+ }
+ Rule_value = map[string]int32{
+ "UNKNOWN": 0,
+ "FILE_NO_BREAKING_CHANGE": 1,
+ "MESSAGE_NO_DELETE": 2,
+ "FIELD_NO_BREAKING_CHANGE": 3,
+ "ENUM_NO_BREAKING_CHANGE": 4,
+ }
+)
+
+func (x Rule) Enum() *Rule {
+ p := new(Rule)
+ *p = x
+ return p
+}
+
+func (x Rule) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Rule) Descriptor() protoreflect.EnumDescriptor {
+ return file_odpf_stencil_v1_stencil_proto_enumTypes[0].Descriptor()
+}
+
+func (Rule) Type() protoreflect.EnumType {
+ return &file_odpf_stencil_v1_stencil_proto_enumTypes[0]
+}
+
+func (x Rule) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Rule.Descriptor instead.
+func (Rule) EnumDescriptor() ([]byte, []int) {
+ return file_odpf_stencil_v1_stencil_proto_rawDescGZIP(), []int{0}
+}
+
+type Snapshot struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+ Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"`
+ Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
+ Version string `protobuf:"bytes,4,opt,name=version,proto3" json:"version,omitempty"`
+ Latest bool `protobuf:"varint,5,opt,name=latest,proto3" json:"latest,omitempty"`
+}
+
+func (x *Snapshot) Reset() {
+ *x = Snapshot{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Snapshot) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Snapshot) ProtoMessage() {}
+
+func (x *Snapshot) ProtoReflect() protoreflect.Message {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Snapshot.ProtoReflect.Descriptor instead.
+func (*Snapshot) Descriptor() ([]byte, []int) {
+ return file_odpf_stencil_v1_stencil_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Snapshot) GetId() int64 {
+ if x != nil {
+ return x.Id
+ }
+ return 0
+}
+
+func (x *Snapshot) GetNamespace() string {
+ if x != nil {
+ return x.Namespace
+ }
+ return ""
+}
+
+func (x *Snapshot) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *Snapshot) GetVersion() string {
+ if x != nil {
+ return x.Version
+ }
+ return ""
+}
+
+func (x *Snapshot) GetLatest() bool {
+ if x != nil {
+ return x.Latest
+ }
+ return false
+}
+
+type DownloadDescriptorRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+ Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"`
+ Fullnames []string `protobuf:"bytes,4,rep,name=fullnames,proto3" json:"fullnames,omitempty"`
+}
+
+func (x *DownloadDescriptorRequest) Reset() {
+ *x = DownloadDescriptorRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *DownloadDescriptorRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DownloadDescriptorRequest) ProtoMessage() {}
+
+func (x *DownloadDescriptorRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DownloadDescriptorRequest.ProtoReflect.Descriptor instead.
+func (*DownloadDescriptorRequest) Descriptor() ([]byte, []int) {
+ return file_odpf_stencil_v1_stencil_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *DownloadDescriptorRequest) GetNamespace() string {
+ if x != nil {
+ return x.Namespace
+ }
+ return ""
+}
+
+func (x *DownloadDescriptorRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *DownloadDescriptorRequest) GetVersion() string {
+ if x != nil {
+ return x.Version
+ }
+ return ""
+}
+
+func (x *DownloadDescriptorRequest) GetFullnames() []string {
+ if x != nil {
+ return x.Fullnames
+ }
+ return nil
+}
+
+type DownloadDescriptorResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
+}
+
+func (x *DownloadDescriptorResponse) Reset() {
+ *x = DownloadDescriptorResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *DownloadDescriptorResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DownloadDescriptorResponse) ProtoMessage() {}
+
+func (x *DownloadDescriptorResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DownloadDescriptorResponse.ProtoReflect.Descriptor instead.
+func (*DownloadDescriptorResponse) Descriptor() ([]byte, []int) {
+ return file_odpf_stencil_v1_stencil_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *DownloadDescriptorResponse) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+type UploadDescriptorRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+ Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"`
+ Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
+ Latest bool `protobuf:"varint,5,opt,name=latest,proto3" json:"latest,omitempty"`
+ Dryrun bool `protobuf:"varint,6,opt,name=dryrun,proto3" json:"dryrun,omitempty"`
+ Checks *Checks `protobuf:"bytes,7,opt,name=checks,proto3" json:"checks,omitempty"`
+}
+
+func (x *UploadDescriptorRequest) Reset() {
+ *x = UploadDescriptorRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UploadDescriptorRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UploadDescriptorRequest) ProtoMessage() {}
+
+func (x *UploadDescriptorRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UploadDescriptorRequest.ProtoReflect.Descriptor instead.
+func (*UploadDescriptorRequest) Descriptor() ([]byte, []int) {
+ return file_odpf_stencil_v1_stencil_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *UploadDescriptorRequest) GetNamespace() string {
+ if x != nil {
+ return x.Namespace
+ }
+ return ""
+}
+
+func (x *UploadDescriptorRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *UploadDescriptorRequest) GetVersion() string {
+ if x != nil {
+ return x.Version
+ }
+ return ""
+}
+
+func (x *UploadDescriptorRequest) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *UploadDescriptorRequest) GetLatest() bool {
+ if x != nil {
+ return x.Latest
+ }
+ return false
+}
+
+func (x *UploadDescriptorRequest) GetDryrun() bool {
+ if x != nil {
+ return x.Dryrun
+ }
+ return false
+}
+
+func (x *UploadDescriptorRequest) GetChecks() *Checks {
+ if x != nil {
+ return x.Checks
+ }
+ return nil
+}
+
+type Checks struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Except []Rule `protobuf:"varint,2,rep,packed,name=except,proto3,enum=odpf.stencil.v1.Rule" json:"except,omitempty"`
+}
+
+func (x *Checks) Reset() {
+ *x = Checks{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Checks) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Checks) ProtoMessage() {}
+
+func (x *Checks) ProtoReflect() protoreflect.Message {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Checks.ProtoReflect.Descriptor instead.
+func (*Checks) Descriptor() ([]byte, []int) {
+ return file_odpf_stencil_v1_stencil_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *Checks) GetExcept() []Rule {
+ if x != nil {
+ return x.Except
+ }
+ return nil
+}
+
+type UploadDescriptorResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
+ Dryrun bool `protobuf:"varint,2,opt,name=dryrun,proto3" json:"dryrun,omitempty"`
+ Errors string `protobuf:"bytes,3,opt,name=errors,proto3" json:"errors,omitempty"`
+}
+
+func (x *UploadDescriptorResponse) Reset() {
+ *x = UploadDescriptorResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UploadDescriptorResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UploadDescriptorResponse) ProtoMessage() {}
+
+func (x *UploadDescriptorResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UploadDescriptorResponse.ProtoReflect.Descriptor instead.
+func (*UploadDescriptorResponse) Descriptor() ([]byte, []int) {
+ return file_odpf_stencil_v1_stencil_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *UploadDescriptorResponse) GetSuccess() bool {
+ if x != nil {
+ return x.Success
+ }
+ return false
+}
+
+func (x *UploadDescriptorResponse) GetDryrun() bool {
+ if x != nil {
+ return x.Dryrun
+ }
+ return false
+}
+
+func (x *UploadDescriptorResponse) GetErrors() string {
+ if x != nil {
+ return x.Errors
+ }
+ return ""
+}
+
+type ListSnapshotsResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Snapshots []*Snapshot `protobuf:"bytes,1,rep,name=snapshots,proto3" json:"snapshots,omitempty"`
+}
+
+func (x *ListSnapshotsResponse) Reset() {
+ *x = ListSnapshotsResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListSnapshotsResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListSnapshotsResponse) ProtoMessage() {}
+
+func (x *ListSnapshotsResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[6]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListSnapshotsResponse.ProtoReflect.Descriptor instead.
+func (*ListSnapshotsResponse) Descriptor() ([]byte, []int) {
+ return file_odpf_stencil_v1_stencil_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *ListSnapshotsResponse) GetSnapshots() []*Snapshot {
+ if x != nil {
+ return x.Snapshots
+ }
+ return nil
+}
+
+type ListSnapshotsRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+ Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"`
+ Latest bool `protobuf:"varint,4,opt,name=latest,proto3" json:"latest,omitempty"`
+}
+
+func (x *ListSnapshotsRequest) Reset() {
+ *x = ListSnapshotsRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ListSnapshotsRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListSnapshotsRequest) ProtoMessage() {}
+
+func (x *ListSnapshotsRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[7]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListSnapshotsRequest.ProtoReflect.Descriptor instead.
+func (*ListSnapshotsRequest) Descriptor() ([]byte, []int) {
+ return file_odpf_stencil_v1_stencil_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *ListSnapshotsRequest) GetNamespace() string {
+ if x != nil {
+ return x.Namespace
+ }
+ return ""
+}
+
+func (x *ListSnapshotsRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *ListSnapshotsRequest) GetVersion() string {
+ if x != nil {
+ return x.Version
+ }
+ return ""
+}
+
+func (x *ListSnapshotsRequest) GetLatest() bool {
+ if x != nil {
+ return x.Latest
+ }
+ return false
+}
+
+type PromoteSnapshotRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+}
+
+func (x *PromoteSnapshotRequest) Reset() {
+ *x = PromoteSnapshotRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *PromoteSnapshotRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PromoteSnapshotRequest) ProtoMessage() {}
+
+func (x *PromoteSnapshotRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[8]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PromoteSnapshotRequest.ProtoReflect.Descriptor instead.
+func (*PromoteSnapshotRequest) Descriptor() ([]byte, []int) {
+ return file_odpf_stencil_v1_stencil_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *PromoteSnapshotRequest) GetId() int64 {
+ if x != nil {
+ return x.Id
+ }
+ return 0
+}
+
+type PromoteSnapshotResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Snapshot *Snapshot `protobuf:"bytes,1,opt,name=snapshot,proto3" json:"snapshot,omitempty"`
+}
+
+func (x *PromoteSnapshotResponse) Reset() {
+ *x = PromoteSnapshotResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *PromoteSnapshotResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PromoteSnapshotResponse) ProtoMessage() {}
+
+func (x *PromoteSnapshotResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_odpf_stencil_v1_stencil_proto_msgTypes[9]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PromoteSnapshotResponse.ProtoReflect.Descriptor instead.
+func (*PromoteSnapshotResponse) Descriptor() ([]byte, []int) {
+ return file_odpf_stencil_v1_stencil_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *PromoteSnapshotResponse) GetSnapshot() *Snapshot {
+ if x != nil {
+ return x.Snapshot
+ }
+ return nil
+}
+
+var File_odpf_stencil_v1_stencil_proto protoreflect.FileDescriptor
+
+var file_odpf_stencil_v1_stencil_proto_rawDesc = []byte{
+ 0x0a, 0x1d, 0x6f, 0x64, 0x70, 0x66, 0x2f, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x2f, 0x76,
+ 0x31, 0x2f, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
+ 0x0f, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x2e, 0x76, 0x31,
+ 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e,
+ 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64,
+ 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
+ 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+ 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70,
+ 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f,
+ 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x22, 0x84, 0x01, 0x0a, 0x08, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x0e,
+ 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x22,
+ 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x09, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
+ 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
+ 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+ 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x22, 0x97, 0x01, 0x0a, 0x19, 0x44, 0x6f, 0x77,
+ 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70,
+ 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52,
+ 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x04, 0x6e, 0x61,
+ 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x04,
+ 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18,
+ 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x07, 0x76, 0x65, 0x72,
+ 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x6e, 0x61, 0x6d, 0x65,
+ 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x6e, 0x61, 0x6d,
+ 0x65, 0x73, 0x22, 0x30, 0x0a, 0x1a, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x44, 0x65,
+ 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04,
+ 0x64, 0x61, 0x74, 0x61, 0x22, 0xf2, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x44,
+ 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x12, 0x22, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73,
+ 0x70, 0x61, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e,
+ 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42,
+ 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18,
+ 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x04, 0xe2, 0x41,
+ 0x01, 0x02, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65,
+ 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74,
+ 0x12, 0x16, 0x0a, 0x06, 0x64, 0x72, 0x79, 0x72, 0x75, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x06, 0x64, 0x72, 0x79, 0x72, 0x75, 0x6e, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x68, 0x65, 0x63,
+ 0x6b, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e,
+ 0x73, 0x74, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b,
+ 0x73, 0x52, 0x06, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x22, 0x37, 0x0a, 0x06, 0x43, 0x68, 0x65,
+ 0x63, 0x6b, 0x73, 0x12, 0x2d, 0x0a, 0x06, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x18, 0x02, 0x20,
+ 0x03, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x73, 0x74, 0x65, 0x6e, 0x63,
+ 0x69, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x06, 0x65, 0x78, 0x63, 0x65,
+ 0x70, 0x74, 0x22, 0x64, 0x0a, 0x18, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x44, 0x65, 0x73, 0x63,
+ 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18,
+ 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
+ 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x72, 0x79, 0x72,
+ 0x75, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x72, 0x79, 0x72, 0x75, 0x6e,
+ 0x12, 0x16, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x22, 0x50, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74,
+ 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x12, 0x37, 0x0a, 0x09, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x18, 0x01,
+ 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x73, 0x74, 0x65, 0x6e,
+ 0x63, 0x69, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52,
+ 0x09, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x22, 0x7a, 0x0a, 0x14, 0x4c, 0x69,
+ 0x73, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65,
+ 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
+ 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18,
+ 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16,
+ 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06,
+ 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x22, 0x28, 0x0a, 0x16, 0x50, 0x72, 0x6f, 0x6d, 0x6f, 0x74,
+ 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64,
+ 0x22, 0x50, 0x0a, 0x17, 0x50, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73,
+ 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x73,
+ 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e,
+ 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x2e, 0x76, 0x31, 0x2e,
+ 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68,
+ 0x6f, 0x74, 0x2a, 0x82, 0x01, 0x0a, 0x04, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55,
+ 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x49, 0x4c, 0x45,
+ 0x5f, 0x4e, 0x4f, 0x5f, 0x42, 0x52, 0x45, 0x41, 0x4b, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x48, 0x41,
+ 0x4e, 0x47, 0x45, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x4d, 0x45, 0x53, 0x53, 0x41, 0x47, 0x45,
+ 0x5f, 0x4e, 0x4f, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x02, 0x12, 0x1c, 0x0a, 0x18,
+ 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x4e, 0x4f, 0x5f, 0x42, 0x52, 0x45, 0x41, 0x4b, 0x49, 0x4e,
+ 0x47, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x10, 0x03, 0x12, 0x1b, 0x0a, 0x17, 0x45, 0x4e,
+ 0x55, 0x4d, 0x5f, 0x4e, 0x4f, 0x5f, 0x42, 0x52, 0x45, 0x41, 0x4b, 0x49, 0x4e, 0x47, 0x5f, 0x43,
+ 0x48, 0x41, 0x4e, 0x47, 0x45, 0x10, 0x04, 0x32, 0xb7, 0x04, 0x0a, 0x0e, 0x53, 0x74, 0x65, 0x6e,
+ 0x63, 0x69, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x93, 0x01, 0x0a, 0x10, 0x55,
+ 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12,
+ 0x28, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x2e, 0x76,
+ 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
+ 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x6f, 0x64, 0x70, 0x66,
+ 0x2e, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x6c, 0x6f,
+ 0x61, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x92, 0x41, 0x27, 0x32, 0x13, 0x6d, 0x75, 0x6c, 0x74, 0x69,
+ 0x70, 0x61, 0x72, 0x74, 0x2f, 0x66, 0x6f, 0x72, 0x6d, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x10,
+ 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e,
+ 0x12, 0x8c, 0x01, 0x0a, 0x12, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x44, 0x65, 0x73,
+ 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x73,
+ 0x74, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f,
+ 0x61, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x73, 0x74, 0x65, 0x6e, 0x63,
+ 0x69, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x44, 0x65,
+ 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x22, 0x1d, 0x92, 0x41, 0x1a, 0x3a, 0x18, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x2f, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12,
+ 0x75, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73,
+ 0x12, 0x25, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x2e,
+ 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x73,
+ 0x74, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e,
+ 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
+ 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x12, 0x0d, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x6e, 0x61,
+ 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x12, 0x88, 0x01, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x6d, 0x6f,
+ 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x27, 0x2e, 0x6f, 0x64, 0x70,
+ 0x66, 0x2e, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f,
+ 0x6d, 0x6f, 0x74, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x73, 0x74, 0x65, 0x6e, 0x63,
+ 0x69, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x53, 0x6e, 0x61,
+ 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82,
+ 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x32, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x6e, 0x61, 0x70, 0x73,
+ 0x68, 0x6f, 0x74, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x70, 0x72, 0x6f, 0x6d, 0x6f, 0x74,
+ 0x65, 0x42, 0x3c, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+ 0x6f, 0x64, 0x70, 0x66, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x2f, 0x73, 0x74, 0x65, 0x6e,
+ 0x63, 0x69, 0x6c, 0x2f, 0x76, 0x31, 0x3b, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x69, 0x6c, 0x76, 0x31,
+ 0x92, 0x41, 0x0c, 0x12, 0x07, 0x32, 0x05, 0x30, 0x2e, 0x31, 0x2e, 0x34, 0x2a, 0x01, 0x01, 0x62,
+ 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_odpf_stencil_v1_stencil_proto_rawDescOnce sync.Once
+ file_odpf_stencil_v1_stencil_proto_rawDescData = file_odpf_stencil_v1_stencil_proto_rawDesc
+)
+
+func file_odpf_stencil_v1_stencil_proto_rawDescGZIP() []byte {
+ file_odpf_stencil_v1_stencil_proto_rawDescOnce.Do(func() {
+ file_odpf_stencil_v1_stencil_proto_rawDescData = protoimpl.X.CompressGZIP(file_odpf_stencil_v1_stencil_proto_rawDescData)
+ })
+ return file_odpf_stencil_v1_stencil_proto_rawDescData
+}
+
+var file_odpf_stencil_v1_stencil_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_odpf_stencil_v1_stencil_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
+var file_odpf_stencil_v1_stencil_proto_goTypes = []interface{}{
+ (Rule)(0), // 0: odpf.stencil.v1.Rule
+ (*Snapshot)(nil), // 1: odpf.stencil.v1.Snapshot
+ (*DownloadDescriptorRequest)(nil), // 2: odpf.stencil.v1.DownloadDescriptorRequest
+ (*DownloadDescriptorResponse)(nil), // 3: odpf.stencil.v1.DownloadDescriptorResponse
+ (*UploadDescriptorRequest)(nil), // 4: odpf.stencil.v1.UploadDescriptorRequest
+ (*Checks)(nil), // 5: odpf.stencil.v1.Checks
+ (*UploadDescriptorResponse)(nil), // 6: odpf.stencil.v1.UploadDescriptorResponse
+ (*ListSnapshotsResponse)(nil), // 7: odpf.stencil.v1.ListSnapshotsResponse
+ (*ListSnapshotsRequest)(nil), // 8: odpf.stencil.v1.ListSnapshotsRequest
+ (*PromoteSnapshotRequest)(nil), // 9: odpf.stencil.v1.PromoteSnapshotRequest
+ (*PromoteSnapshotResponse)(nil), // 10: odpf.stencil.v1.PromoteSnapshotResponse
+}
+var file_odpf_stencil_v1_stencil_proto_depIdxs = []int32{
+ 5, // 0: odpf.stencil.v1.UploadDescriptorRequest.checks:type_name -> odpf.stencil.v1.Checks
+ 0, // 1: odpf.stencil.v1.Checks.except:type_name -> odpf.stencil.v1.Rule
+ 1, // 2: odpf.stencil.v1.ListSnapshotsResponse.snapshots:type_name -> odpf.stencil.v1.Snapshot
+ 1, // 3: odpf.stencil.v1.PromoteSnapshotResponse.snapshot:type_name -> odpf.stencil.v1.Snapshot
+ 4, // 4: odpf.stencil.v1.StencilService.UploadDescriptor:input_type -> odpf.stencil.v1.UploadDescriptorRequest
+ 2, // 5: odpf.stencil.v1.StencilService.DownloadDescriptor:input_type -> odpf.stencil.v1.DownloadDescriptorRequest
+ 8, // 6: odpf.stencil.v1.StencilService.ListSnapshots:input_type -> odpf.stencil.v1.ListSnapshotsRequest
+ 9, // 7: odpf.stencil.v1.StencilService.PromoteSnapshot:input_type -> odpf.stencil.v1.PromoteSnapshotRequest
+ 6, // 8: odpf.stencil.v1.StencilService.UploadDescriptor:output_type -> odpf.stencil.v1.UploadDescriptorResponse
+ 3, // 9: odpf.stencil.v1.StencilService.DownloadDescriptor:output_type -> odpf.stencil.v1.DownloadDescriptorResponse
+ 7, // 10: odpf.stencil.v1.StencilService.ListSnapshots:output_type -> odpf.stencil.v1.ListSnapshotsResponse
+ 10, // 11: odpf.stencil.v1.StencilService.PromoteSnapshot:output_type -> odpf.stencil.v1.PromoteSnapshotResponse
+ 8, // [8:12] is the sub-list for method output_type
+ 4, // [4:8] is the sub-list for method input_type
+ 4, // [4:4] is the sub-list for extension type_name
+ 4, // [4:4] is the sub-list for extension extendee
+ 0, // [0:4] is the sub-list for field type_name
+}
+
+func init() { file_odpf_stencil_v1_stencil_proto_init() }
+func file_odpf_stencil_v1_stencil_proto_init() {
+ if File_odpf_stencil_v1_stencil_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_odpf_stencil_v1_stencil_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Snapshot); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_odpf_stencil_v1_stencil_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*DownloadDescriptorRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_odpf_stencil_v1_stencil_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*DownloadDescriptorResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_odpf_stencil_v1_stencil_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UploadDescriptorRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_odpf_stencil_v1_stencil_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Checks); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_odpf_stencil_v1_stencil_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UploadDescriptorResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_odpf_stencil_v1_stencil_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ListSnapshotsResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_odpf_stencil_v1_stencil_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ListSnapshotsRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_odpf_stencil_v1_stencil_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*PromoteSnapshotRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_odpf_stencil_v1_stencil_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*PromoteSnapshotResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_odpf_stencil_v1_stencil_proto_rawDesc,
+ NumEnums: 1,
+ NumMessages: 10,
+ NumExtensions: 0,
+ NumServices: 1,
+ },
+ GoTypes: file_odpf_stencil_v1_stencil_proto_goTypes,
+ DependencyIndexes: file_odpf_stencil_v1_stencil_proto_depIdxs,
+ EnumInfos: file_odpf_stencil_v1_stencil_proto_enumTypes,
+ MessageInfos: file_odpf_stencil_v1_stencil_proto_msgTypes,
+ }.Build()
+ File_odpf_stencil_v1_stencil_proto = out.File
+ file_odpf_stencil_v1_stencil_proto_rawDesc = nil
+ file_odpf_stencil_v1_stencil_proto_goTypes = nil
+ file_odpf_stencil_v1_stencil_proto_depIdxs = nil
+}
diff --git a/server/odpf/stencil/v1/stencil.pb.gw.go b/server/odpf/stencil/v1/stencil.pb.gw.go
new file mode 100644
index 00000000..5116dd6b
--- /dev/null
+++ b/server/odpf/stencil/v1/stencil.pb.gw.go
@@ -0,0 +1,268 @@
+// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
+// source: odpf/stencil/v1/stencil.proto
+
+/*
+Package stencilv1 is a reverse proxy.
+
+It translates gRPC into RESTful JSON APIs.
+*/
+package stencilv1
+
+import (
+ "context"
+ "io"
+ "net/http"
+
+ "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
+ "github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/grpclog"
+ "google.golang.org/grpc/metadata"
+ "google.golang.org/grpc/status"
+ "google.golang.org/protobuf/proto"
+)
+
+// Suppress "imported and not used" errors
+var _ codes.Code
+var _ io.Reader
+var _ status.Status
+var _ = runtime.String
+var _ = utilities.NewDoubleArray
+var _ = metadata.Join
+
+var (
+ filter_StencilService_ListSnapshots_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
+)
+
+func request_StencilService_ListSnapshots_0(ctx context.Context, marshaler runtime.Marshaler, client StencilServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq ListSnapshotsRequest
+ var metadata runtime.ServerMetadata
+
+ if err := req.ParseForm(); err != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+ }
+ if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_StencilService_ListSnapshots_0); err != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+ }
+
+ msg, err := client.ListSnapshots(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+ return msg, metadata, err
+
+}
+
+func local_request_StencilService_ListSnapshots_0(ctx context.Context, marshaler runtime.Marshaler, server StencilServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq ListSnapshotsRequest
+ var metadata runtime.ServerMetadata
+
+ if err := req.ParseForm(); err != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+ }
+ if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_StencilService_ListSnapshots_0); err != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+ }
+
+ msg, err := server.ListSnapshots(ctx, &protoReq)
+ return msg, metadata, err
+
+}
+
+func request_StencilService_PromoteSnapshot_0(ctx context.Context, marshaler runtime.Marshaler, client StencilServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq PromoteSnapshotRequest
+ var metadata runtime.ServerMetadata
+
+ var (
+ val string
+ ok bool
+ err error
+ _ = err
+ )
+
+ val, ok = pathParams["id"]
+ if !ok {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
+ }
+
+ protoReq.Id, err = runtime.Int64(val)
+ if err != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
+ }
+
+ msg, err := client.PromoteSnapshot(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+ return msg, metadata, err
+
+}
+
+func local_request_StencilService_PromoteSnapshot_0(ctx context.Context, marshaler runtime.Marshaler, server StencilServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq PromoteSnapshotRequest
+ var metadata runtime.ServerMetadata
+
+ var (
+ val string
+ ok bool
+ err error
+ _ = err
+ )
+
+ val, ok = pathParams["id"]
+ if !ok {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
+ }
+
+ protoReq.Id, err = runtime.Int64(val)
+ if err != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
+ }
+
+ msg, err := server.PromoteSnapshot(ctx, &protoReq)
+ return msg, metadata, err
+
+}
+
+// RegisterStencilServiceHandlerServer registers the http handlers for service StencilService to "mux".
+// UnaryRPC :call StencilServiceServer directly.
+// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
+// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterStencilServiceHandlerFromEndpoint instead.
+func RegisterStencilServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server StencilServiceServer) error {
+
+ mux.Handle("GET", pattern_StencilService_ListSnapshots_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ var stream runtime.ServerTransportStream
+ ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/odpf.stencil.v1.StencilService/ListSnapshots", runtime.WithHTTPPathPattern("/v1/snapshots"))
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := local_request_StencilService_ListSnapshots_0(rctx, inboundMarshaler, server, req, pathParams)
+ md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
+ ctx = runtime.NewServerMetadataContext(ctx, md)
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_StencilService_ListSnapshots_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ mux.Handle("PATCH", pattern_StencilService_PromoteSnapshot_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ var stream runtime.ServerTransportStream
+ ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/odpf.stencil.v1.StencilService/PromoteSnapshot", runtime.WithHTTPPathPattern("/v1/snapshots/{id}/promote"))
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := local_request_StencilService_PromoteSnapshot_0(rctx, inboundMarshaler, server, req, pathParams)
+ md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
+ ctx = runtime.NewServerMetadataContext(ctx, md)
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_StencilService_PromoteSnapshot_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ return nil
+}
+
+// RegisterStencilServiceHandlerFromEndpoint is same as RegisterStencilServiceHandler but
+// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
+func RegisterStencilServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
+ conn, err := grpc.Dial(endpoint, opts...)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if err != nil {
+ if cerr := conn.Close(); cerr != nil {
+ grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
+ }
+ return
+ }
+ go func() {
+ <-ctx.Done()
+ if cerr := conn.Close(); cerr != nil {
+ grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
+ }
+ }()
+ }()
+
+ return RegisterStencilServiceHandler(ctx, mux, conn)
+}
+
+// RegisterStencilServiceHandler registers the http handlers for service StencilService to "mux".
+// The handlers forward requests to the grpc endpoint over "conn".
+func RegisterStencilServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
+ return RegisterStencilServiceHandlerClient(ctx, mux, NewStencilServiceClient(conn))
+}
+
+// RegisterStencilServiceHandlerClient registers the http handlers for service StencilService
+// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "StencilServiceClient".
+// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "StencilServiceClient"
+// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
+// "StencilServiceClient" to call the correct interceptors.
+func RegisterStencilServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client StencilServiceClient) error {
+
+ mux.Handle("GET", pattern_StencilService_ListSnapshots_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ rctx, err := runtime.AnnotateContext(ctx, mux, req, "/odpf.stencil.v1.StencilService/ListSnapshots", runtime.WithHTTPPathPattern("/v1/snapshots"))
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := request_StencilService_ListSnapshots_0(rctx, inboundMarshaler, client, req, pathParams)
+ ctx = runtime.NewServerMetadataContext(ctx, md)
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_StencilService_ListSnapshots_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ mux.Handle("PATCH", pattern_StencilService_PromoteSnapshot_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ rctx, err := runtime.AnnotateContext(ctx, mux, req, "/odpf.stencil.v1.StencilService/PromoteSnapshot", runtime.WithHTTPPathPattern("/v1/snapshots/{id}/promote"))
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := request_StencilService_PromoteSnapshot_0(rctx, inboundMarshaler, client, req, pathParams)
+ ctx = runtime.NewServerMetadataContext(ctx, md)
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_StencilService_PromoteSnapshot_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ return nil
+}
+
+var (
+ pattern_StencilService_ListSnapshots_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "snapshots"}, ""))
+
+ pattern_StencilService_PromoteSnapshot_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"v1", "snapshots", "id", "promote"}, ""))
+)
+
+var (
+ forward_StencilService_ListSnapshots_0 = runtime.ForwardResponseMessage
+
+ forward_StencilService_PromoteSnapshot_0 = runtime.ForwardResponseMessage
+)
diff --git a/server/odpf/stencil/v1/stencil_grpc.pb.go b/server/odpf/stencil/v1/stencil_grpc.pb.go
new file mode 100644
index 00000000..33fe5c55
--- /dev/null
+++ b/server/odpf/stencil/v1/stencil_grpc.pb.go
@@ -0,0 +1,211 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package stencilv1
+
+import (
+ context "context"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// StencilServiceClient is the client API for StencilService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type StencilServiceClient interface {
+ UploadDescriptor(ctx context.Context, in *UploadDescriptorRequest, opts ...grpc.CallOption) (*UploadDescriptorResponse, error)
+ DownloadDescriptor(ctx context.Context, in *DownloadDescriptorRequest, opts ...grpc.CallOption) (*DownloadDescriptorResponse, error)
+ ListSnapshots(ctx context.Context, in *ListSnapshotsRequest, opts ...grpc.CallOption) (*ListSnapshotsResponse, error)
+ // PromoteSnapshot promotes particular snapshot version as latest
+ PromoteSnapshot(ctx context.Context, in *PromoteSnapshotRequest, opts ...grpc.CallOption) (*PromoteSnapshotResponse, error)
+}
+
+type stencilServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewStencilServiceClient(cc grpc.ClientConnInterface) StencilServiceClient {
+ return &stencilServiceClient{cc}
+}
+
+func (c *stencilServiceClient) UploadDescriptor(ctx context.Context, in *UploadDescriptorRequest, opts ...grpc.CallOption) (*UploadDescriptorResponse, error) {
+ out := new(UploadDescriptorResponse)
+ err := c.cc.Invoke(ctx, "/odpf.stencil.v1.StencilService/UploadDescriptor", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *stencilServiceClient) DownloadDescriptor(ctx context.Context, in *DownloadDescriptorRequest, opts ...grpc.CallOption) (*DownloadDescriptorResponse, error) {
+ out := new(DownloadDescriptorResponse)
+ err := c.cc.Invoke(ctx, "/odpf.stencil.v1.StencilService/DownloadDescriptor", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *stencilServiceClient) ListSnapshots(ctx context.Context, in *ListSnapshotsRequest, opts ...grpc.CallOption) (*ListSnapshotsResponse, error) {
+ out := new(ListSnapshotsResponse)
+ err := c.cc.Invoke(ctx, "/odpf.stencil.v1.StencilService/ListSnapshots", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *stencilServiceClient) PromoteSnapshot(ctx context.Context, in *PromoteSnapshotRequest, opts ...grpc.CallOption) (*PromoteSnapshotResponse, error) {
+ out := new(PromoteSnapshotResponse)
+ err := c.cc.Invoke(ctx, "/odpf.stencil.v1.StencilService/PromoteSnapshot", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// StencilServiceServer is the server API for StencilService service.
+// All implementations must embed UnimplementedStencilServiceServer
+// for forward compatibility
+type StencilServiceServer interface {
+ UploadDescriptor(context.Context, *UploadDescriptorRequest) (*UploadDescriptorResponse, error)
+ DownloadDescriptor(context.Context, *DownloadDescriptorRequest) (*DownloadDescriptorResponse, error)
+ ListSnapshots(context.Context, *ListSnapshotsRequest) (*ListSnapshotsResponse, error)
+ // PromoteSnapshot promotes particular snapshot version as latest
+ PromoteSnapshot(context.Context, *PromoteSnapshotRequest) (*PromoteSnapshotResponse, error)
+ mustEmbedUnimplementedStencilServiceServer()
+}
+
+// UnimplementedStencilServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedStencilServiceServer struct {
+}
+
+func (UnimplementedStencilServiceServer) UploadDescriptor(context.Context, *UploadDescriptorRequest) (*UploadDescriptorResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method UploadDescriptor not implemented")
+}
+func (UnimplementedStencilServiceServer) DownloadDescriptor(context.Context, *DownloadDescriptorRequest) (*DownloadDescriptorResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method DownloadDescriptor not implemented")
+}
+func (UnimplementedStencilServiceServer) ListSnapshots(context.Context, *ListSnapshotsRequest) (*ListSnapshotsResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method ListSnapshots not implemented")
+}
+func (UnimplementedStencilServiceServer) PromoteSnapshot(context.Context, *PromoteSnapshotRequest) (*PromoteSnapshotResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method PromoteSnapshot not implemented")
+}
+func (UnimplementedStencilServiceServer) mustEmbedUnimplementedStencilServiceServer() {}
+
+// UnsafeStencilServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to StencilServiceServer will
+// result in compilation errors.
+type UnsafeStencilServiceServer interface {
+ mustEmbedUnimplementedStencilServiceServer()
+}
+
+func RegisterStencilServiceServer(s grpc.ServiceRegistrar, srv StencilServiceServer) {
+ s.RegisterService(&StencilService_ServiceDesc, srv)
+}
+
+func _StencilService_UploadDescriptor_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UploadDescriptorRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(StencilServiceServer).UploadDescriptor(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/odpf.stencil.v1.StencilService/UploadDescriptor",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(StencilServiceServer).UploadDescriptor(ctx, req.(*UploadDescriptorRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _StencilService_DownloadDescriptor_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(DownloadDescriptorRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(StencilServiceServer).DownloadDescriptor(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/odpf.stencil.v1.StencilService/DownloadDescriptor",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(StencilServiceServer).DownloadDescriptor(ctx, req.(*DownloadDescriptorRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _StencilService_ListSnapshots_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ListSnapshotsRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(StencilServiceServer).ListSnapshots(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/odpf.stencil.v1.StencilService/ListSnapshots",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(StencilServiceServer).ListSnapshots(ctx, req.(*ListSnapshotsRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _StencilService_PromoteSnapshot_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(PromoteSnapshotRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(StencilServiceServer).PromoteSnapshot(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/odpf.stencil.v1.StencilService/PromoteSnapshot",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(StencilServiceServer).PromoteSnapshot(ctx, req.(*PromoteSnapshotRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// StencilService_ServiceDesc is the grpc.ServiceDesc for StencilService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var StencilService_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "odpf.stencil.v1.StencilService",
+ HandlerType: (*StencilServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "UploadDescriptor",
+ Handler: _StencilService_UploadDescriptor_Handler,
+ },
+ {
+ MethodName: "DownloadDescriptor",
+ Handler: _StencilService_DownloadDescriptor_Handler,
+ },
+ {
+ MethodName: "ListSnapshots",
+ Handler: _StencilService_ListSnapshots_Handler,
+ },
+ {
+ MethodName: "PromoteSnapshot",
+ Handler: _StencilService_PromoteSnapshot_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "odpf/stencil/v1/stencil.proto",
+}
diff --git a/server/proto/service.go b/server/proto/service.go
index 9138d1c8..358cab4a 100644
--- a/server/proto/service.go
+++ b/server/proto/service.go
@@ -15,11 +15,11 @@ type Service struct {
// Validate checks if current data is backward compatible against previous stable data
func (s *Service) Validate(ctx context.Context, cs *snapshot.Snapshot, data []byte, rulesToSkip []string) error {
var err error
- prevSt, err := s.snapshotRepo.GetSnapshot(ctx, cs.Namespace, cs.Name, "", true)
+ prevSt, err := s.snapshotRepo.GetSnapshotByFields(ctx, cs.Namespace, cs.Name, "", true)
if err == snapshot.ErrNotFound {
return nil
}
- // no need to handle error here. Since without snapshot data won't exist.
+ // no need to handle error here. Since without snapshot, data won't exist.
// If snapshot exist and data is nil, then validation still passes as it's treated as completely new
prevData, _ := s.Get(ctx, prevSt, []string{})
return Compare(data, prevData, rulesToSkip)
diff --git a/server/server/graceful.go b/server/server/graceful.go
index 4cc9fb00..b7220c23 100644
--- a/server/server/graceful.go
+++ b/server/server/graceful.go
@@ -10,11 +10,10 @@ import (
"os/signal"
"syscall"
- "github.com/gin-gonic/gin"
"github.com/odpf/stencil/server/config"
)
-func runWithGracefulShutdown(config *config.Config, router *gin.Engine, cleanUp func()) {
+func runWithGracefulShutdown(config *config.Config, router http.Handler, cleanUp func()) {
srv := &http.Server{
Addr: fmt.Sprintf(":%s", config.Port),
Handler: router,
diff --git a/server/server/middleware.go b/server/server/middleware.go
index 2f6514fd..5fd8d2e7 100644
--- a/server/server/middleware.go
+++ b/server/server/middleware.go
@@ -5,8 +5,11 @@ import (
"time"
"github.com/gin-gonic/gin"
+ "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
+ "github.com/newrelic/go-agent/v3/integrations/nrgin"
"github.com/odpf/stencil/server/config"
"github.com/odpf/stencil/server/models"
+ "google.golang.org/grpc/status"
)
func errorHandle() gin.HandlerFunc {
@@ -16,6 +19,15 @@ func errorHandle() gin.HandlerFunc {
if ginErr == nil {
return
}
+ if err, ok := status.FromError(ginErr.Err); ok {
+ code := runtime.HTTPStatusFromCode(err.Code())
+ msg := err.Message()
+ if code >= 500 {
+ msg = "Internal error"
+ }
+ c.AbortWithStatusJSON(code, gin.H{"message": msg})
+ return
+ }
if err, ok := ginErr.Err.(models.APIError); ok {
c.AbortWithStatusJSON(err.Code(), gin.H{"message": err.Message()})
return
@@ -37,7 +49,7 @@ func getLogger() gin.HandlerFunc {
}
func addMiddleware(router *gin.Engine, config *config.Config) {
- router.Use(getNewRelicMiddleware(config))
+ router.Use(nrgin.Middleware(getNewRelic(config)))
router.Use(gin.Recovery())
router.Use(getLogger())
router.Use(errorHandle())
diff --git a/server/server/newrelic.go b/server/server/newrelic.go
index 9244d5dc..12fcc97b 100644
--- a/server/server/newrelic.go
+++ b/server/server/newrelic.go
@@ -3,13 +3,11 @@ package server
import (
"log"
- "github.com/gin-gonic/gin"
- "github.com/newrelic/go-agent/v3/integrations/nrgin"
"github.com/newrelic/go-agent/v3/newrelic"
"github.com/odpf/stencil/server/config"
)
-func getNewRelicMiddleware(config *config.Config) gin.HandlerFunc {
+func getNewRelic(config *config.Config) *newrelic.Application {
newRelicConfig := config.NewRelic
app, err := newrelic.NewApplication(
newrelic.ConfigAppName(newRelicConfig.AppName),
@@ -19,5 +17,5 @@ func getNewRelicMiddleware(config *config.Config) gin.HandlerFunc {
if err != nil {
log.Fatal(err)
}
- return nrgin.Middleware(app)
+ return app
}
diff --git a/server/server/routes.go b/server/server/routes.go
index de02d6d4..34002b1c 100644
--- a/server/server/routes.go
+++ b/server/server/routes.go
@@ -1,18 +1,25 @@
package server
import (
+ "net/http"
+
"github.com/gin-gonic/gin"
+ "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/odpf/stencil/server/api"
)
-func registerRoutes(router *gin.Engine, handlers *api.API) {
+func proxyToGin(e *gin.Engine) func(http.ResponseWriter, *http.Request, map[string]string) {
+ return func(rw http.ResponseWriter, r *http.Request, m map[string]string) {
+ e.ServeHTTP(rw, r)
+ }
+}
+
+func registerRoutes(router *gin.Engine, mux *runtime.ServeMux, handlers *api.API) {
apiV1 := router.Group("/v1/namespaces/:namespace")
- router.NoRoute(api.NoRoute)
router.GET("/ping", api.Ping)
- apiV1.POST("/descriptors", handlers.Upload)
- apiV1.GET("/descriptors", handlers.ListNames)
- apiV1.GET("/descriptors/:name/versions", handlers.ListVersions)
- apiV1.GET("/descriptors/:name/versions/:version", handlers.Download)
- apiV1.GET("/metadata/:name", handlers.GetLatestVersion)
- apiV1.POST("/metadata", handlers.UpdateLatestVersion)
+ apiV1.POST("/descriptors", handlers.HTTPUpload)
+ apiV1.GET("/descriptors/:name/versions/:version", handlers.HTTPDownload)
+ mux.HandlePath("GET", "/ping", proxyToGin(router))
+ mux.HandlePath("GET", "/v1/namespaces/{namespace}/descriptors/{name}/versions/{version}", proxyToGin(router))
+ mux.HandlePath("POST", "/v1/namespaces/{namespace}/descriptors", proxyToGin(router))
}
diff --git a/server/server/server.go b/server/server/server.go
index 924e63d6..e3d492ed 100644
--- a/server/server/server.go
+++ b/server/server/server.go
@@ -1,38 +1,100 @@
package server
import (
+ "context"
+ "fmt"
+ "log"
+ "net/http"
+ "strings"
+
"github.com/gin-gonic/gin"
+ "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
+ "github.com/newrelic/go-agent/v3/integrations/nrgrpc"
+
+ grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
+ grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
+ grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
+ grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
"github.com/odpf/stencil/server/api"
"github.com/odpf/stencil/server/config"
+ "github.com/odpf/stencil/server/logger"
+ stencilv1 "github.com/odpf/stencil/server/odpf/stencil/v1"
"github.com/odpf/stencil/server/proto"
"github.com/odpf/stencil/server/snapshot"
"github.com/odpf/stencil/server/store"
+ "golang.org/x/net/http2"
+ "golang.org/x/net/http2/h2c"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/health/grpc_health_v1"
)
// Router returns server router
-func Router(api *api.API, config *config.Config) *gin.Engine {
+func Router(api *api.API, config *config.Config) *runtime.ServeMux {
+ gwmux := runtime.NewServeMux()
router := gin.New()
addMiddleware(router, config)
registerCustomValidations(router)
- registerRoutes(router, api)
- return router
+ registerRoutes(router, gwmux, api)
+ return gwmux
}
// Start Entry point to start the server
func Start() {
+ ctx := context.Background()
config := config.LoadConfig()
db := store.NewDBStore(config)
stRepo := snapshot.NewSnapshotRepository(db)
- stSvc := snapshot.NewSnapshotService(stRepo)
protoRepo := proto.NewProtoRepository(db)
protoService := proto.NewService(protoRepo, stRepo)
api := &api.API{
Store: protoService,
- Metadata: stSvc,
+ Metadata: stRepo,
+ }
+ port := fmt.Sprintf(":%s", config.Port)
+ nr := getNewRelic(config)
+ mux := Router(api, config)
+
+ // init grpc server
+ opts := []grpc.ServerOption{
+ grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
+ grpc_recovery.UnaryServerInterceptor(),
+ grpc_ctxtags.UnaryServerInterceptor(),
+ nrgrpc.UnaryServerInterceptor(nr),
+ grpc_zap.UnaryServerInterceptor(logger.Logger))),
+ grpc.MaxRecvMsgSize(config.GRPC.MaxRecvMsgSizeInMB << 20),
+ grpc.MaxSendMsgSize(config.GRPC.MaxSendMsgSizeInMB << 20),
}
- router := Router(api, config)
+ // Create a gRPC server object
+ s := grpc.NewServer(opts...)
+ stencilv1.RegisterStencilServiceServer(s, api)
+ grpc_health_v1.RegisterHealthServer(s, api)
+ conn, err := grpc.DialContext(
+ context.Background(),
+ port,
+ grpc.WithInsecure(),
+ )
+ if err != nil {
+ log.Fatalln("Failed to dial server:", err)
+ }
+
+ stencilv1.RegisterStencilServiceHandler(ctx, mux, conn)
- runWithGracefulShutdown(config, router, func() {
- db.Pool.Close()
+ runWithGracefulShutdown(config, grpcHandlerFunc(s, mux), func() {
+ conn.Close()
+ s.GracefulStop()
+ db.Close()
})
}
+
+// grpcHandlerFunc returns an http.Handler that delegates to grpcServer on incoming gRPC
+// connections or otherHandler otherwise.
+func grpcHandlerFunc(grpcServer *grpc.Server, otherHandler http.Handler) http.Handler {
+ return h2c.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ // This is a partial recreation of gRPC's internal checks https://github.com/grpc/grpc-go/pull/514/files#diff-95e9a25b738459a2d3030e1e6fa2a718R61
+ if r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
+ grpcServer.ServeHTTP(w, r)
+ } else {
+ otherHandler.ServeHTTP(w, r)
+ }
+ }), &http2.Server{})
+}
diff --git a/server/server/validation.go b/server/server/validation.go
index 5cb2612b..f3cc13ee 100644
--- a/server/server/validation.go
+++ b/server/server/validation.go
@@ -19,21 +19,8 @@ func ValidateVersion(fl validator.FieldLevel) bool {
return false
}
-//ValidateVersionWithLatest validates if value is equal to latest or valid semantic version
-func ValidateVersionWithLatest(fl validator.FieldLevel) bool {
- version, ok := fl.Field().Interface().(string)
- if ok {
- if _, err := semver.Parse(version); err == nil {
- return true
- }
- return version == "latest"
- }
- return false
-}
-
func registerCustomValidations(e *gin.Engine) {
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
v.RegisterValidation("version", ValidateVersion)
- v.RegisterValidation("versionWithLatest", ValidateVersionWithLatest)
}
}
diff --git a/server/snapshot/model.go b/server/snapshot/model.go
index c2008f5e..1b775a2a 100644
--- a/server/snapshot/model.go
+++ b/server/snapshot/model.go
@@ -1,6 +1,8 @@
package snapshot
-import "errors"
+import (
+ "errors"
+)
var (
//ErrNotFound used when snapshot is not found
@@ -9,9 +11,9 @@ var (
// Snapshot represents specific version of protodescriptorset
type Snapshot struct {
- ID int64
- Namespace string
- Name string
- Version string
- Latest bool
+ ID int64 `binding:"required"`
+ Namespace string `binding:"required"`
+ Name string `binding:"required"`
+ Version string `binding:"required,version"`
+ Latest bool `binding:"required"`
}
diff --git a/server/snapshot/repository.go b/server/snapshot/repository.go
index f9a1696f..24e9412b 100644
--- a/server/snapshot/repository.go
+++ b/server/snapshot/repository.go
@@ -2,6 +2,7 @@ package snapshot
import (
"context"
+ "fmt"
"strings"
"github.com/georgysavva/scany/pgxscan"
@@ -34,29 +35,39 @@ type Repository struct {
db *store.DB
}
-// ListNames returns names
-func (r *Repository) ListNames(ctx context.Context, namespace string) ([]string, error) {
- var names []string
- err := pgxscan.Select(ctx, r.db, &names, `SELECT DISTINCT(name) from snapshots where namespace=$1`, namespace)
- return names, err
-}
-
-// ListVersions returns versions
-func (r *Repository) ListVersions(ctx context.Context, namespace string, name string) ([]string, error) {
- var names []string
- err := pgxscan.Select(ctx, r.db, &names, `SELECT version from snapshots where namespace=$1 and name=$2`, namespace, name)
- return names, err
-}
-
-// Exists checks if mentioned version is present or not
-func (r *Repository) Exists(ctx context.Context, snapshot *Snapshot) bool {
- var count int64
- err := r.db.QueryRow(ctx, `SELECT count(id) from snapshots where namespace=$1 and name=$2 and version=$3`,
- snapshot.Namespace, snapshot.Name, snapshot.Version).Scan(&count)
- if err != nil {
- return false
+// List returns list of snapshots
+func (r *Repository) List(ctx context.Context, queryFields *Snapshot) ([]*Snapshot, error) {
+ var snapshots []*Snapshot
+ var query strings.Builder
+ var args []interface{}
+ var conditions []string
+ query.WriteString(`SELECT * from snapshots`)
+ if queryFields.Latest {
+ conditions = append(conditions, "latest=true")
+ }
+ if queryFields.Namespace != "" {
+ conditions = append(conditions, fmt.Sprintf("namespace=$%d", len(args)+1))
+ args = append(args, queryFields.Namespace)
+ }
+ if queryFields.Name != "" {
+ conditions = append(conditions, fmt.Sprintf("name=$%d", len(args)+1))
+ args = append(args, queryFields.Name)
+ }
+ if queryFields.Version != "" {
+ conditions = append(conditions, fmt.Sprintf("version=$%d", len(args)+1))
+ args = append(args, queryFields.Version)
+ }
+ if queryFields.ID != 0 {
+ conditions = append(conditions, fmt.Sprintf("id=$%d", len(args)+1))
+ args = append(args, queryFields.ID)
+ }
+ if len(conditions) > 0 {
+ condition := strings.Join(conditions, " AND ")
+ query.WriteString(fmt.Sprintf(` WHERE %s`, condition))
}
- return count != 0
+
+ err := pgxscan.Select(ctx, r.db, &snapshots, query.String(), args...)
+ return snapshots, err
}
// UpdateLatestVersion returns latest version number
@@ -72,25 +83,26 @@ func (r *Repository) UpdateLatestVersion(ctx context.Context, snapshot *Snapshot
return err
}
_, err = t.Exec(ctx, `UPDATE snapshots set latest=true where id=$1`, snapshot.ID)
- return err
+ if err != nil {
+ return err
+ }
+ snapshot.Latest = true
+ return nil
})
}
-// GetSnapshot returns full snapshot data
-func (r *Repository) GetSnapshot(ctx context.Context, namespace, name, version string, latest bool) (*Snapshot, error) {
+// GetSnapshotByFields returns full snapshot data
+func (r *Repository) GetSnapshotByFields(ctx context.Context, namespace, name, version string, latest bool) (*Snapshot, error) {
snapshot := &Snapshot{
Namespace: namespace,
Name: name,
}
var query strings.Builder
var args []interface{}
- query.WriteString(`SELECT id, version, latest from snapshots where namespace=$1 and name=$2`)
- args = append(args, namespace, name)
- if latest {
- query.WriteString(` and latest=true`)
- }
+ query.WriteString(`SELECT id, version, latest from snapshots where namespace=$1 and name=$2 and latest=$3`)
+ args = append(args, namespace, name, latest)
if version != "" {
- query.WriteString(` and version=$3`)
+ query.WriteString(` and version=$4`)
args = append(args, version)
}
err := r.db.QueryRow(ctx, query.String(), args...).Scan(&snapshot.ID, &snapshot.Version, &snapshot.Latest)
@@ -100,6 +112,22 @@ func (r *Repository) GetSnapshot(ctx context.Context, namespace, name, version s
return snapshot, err
}
+// GetSnapshotByID get snapshot by ID
+func (r *Repository) GetSnapshotByID(ctx context.Context, id int64) (*Snapshot, error) {
+ var s Snapshot
+ err := r.db.QueryRow(ctx, `SELECT * FROM snapshots where id=$1`, id).Scan(&s.ID, &s.Namespace, &s.Name, &s.Version, &s.Latest)
+ if err == pgx.ErrNoRows {
+ return &s, ErrNotFound
+ }
+ return &s, err
+}
+
+// Exists checks if snapshot exits in DB or not
+func (r *Repository) Exists(ctx context.Context, st *Snapshot) bool {
+ l, err := r.List(ctx, st)
+ return err == nil && len(l) > 0
+}
+
// Create inserts snapshot data
func (r *Repository) Create(ctx context.Context, snapshot *Snapshot) error {
return r.db.QueryRow(ctx, snapshotInsertQuery, snapshot.Namespace, snapshot.Name, snapshot.Version).Scan(&snapshot.ID)
diff --git a/server/snapshot/service.go b/server/snapshot/service.go
deleted file mode 100644
index ffb2e521..00000000
--- a/server/snapshot/service.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package snapshot
-
-import (
- "context"
-)
-
-// Service handles snapshot CRUD operations
-type Service struct {
- repo *Repository
-}
-
-// ListNames returns list of available proto descriptorset names under specified namespace
-func (s *Service) ListNames(ctx context.Context, namespace string) ([]string, error) {
- return s.repo.ListNames(ctx, namespace)
-}
-
-// ListVersions returns list of available versions
-func (s *Service) ListVersions(ctx context.Context, namespace, name string) ([]string, error) {
- return s.repo.ListVersions(ctx, namespace, name)
-}
-
-// GetSnapshot returns latest version number
-func (s *Service) GetSnapshot(ctx context.Context, namespace, name, version string, latest bool) (*Snapshot, error) {
- return s.repo.GetSnapshot(ctx, namespace, name, version, latest)
-}
-
-// UpdateLatestVersion updates latest version number for snapshot
-func (s *Service) UpdateLatestVersion(ctx context.Context, st *Snapshot) error {
- snapshotWithID, err := s.repo.GetSnapshot(ctx, st.Namespace, st.Name, st.Version, st.Latest)
- if err != nil {
- return err
- }
- return s.repo.UpdateLatestVersion(ctx, snapshotWithID)
-}
-
-// Exists check if snapshot exists or not
-func (s *Service) Exists(ctx context.Context, snapshot *Snapshot) bool {
- return s.repo.Exists(ctx, snapshot)
-}
-
-// NewSnapshotService creates new instance of proto service
-func NewSnapshotService(r *Repository) *Service {
- return &Service{r}
-}
diff --git a/server/store/db.go b/server/store/db.go
index c9b709d1..2b49c91f 100644
--- a/server/store/db.go
+++ b/server/store/db.go
@@ -4,11 +4,10 @@ import (
"context"
"log"
- "github.com/jackc/pgx/v4"
"github.com/jackc/pgx/v4/log/zapadapter"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/odpf/stencil/server/config"
- "go.uber.org/zap"
+ "github.com/odpf/stencil/server/logger"
)
// DB db instance
@@ -19,12 +18,7 @@ type DB struct {
// NewDBStore create DB store
func NewDBStore(dbConfig *config.Config) *DB {
cc, _ := pgxpool.ParseConfig(dbConfig.DB.ConnectionString)
- logger, err := zap.NewProduction()
- if err != nil {
- log.Fatal(err)
- }
- cc.ConnConfig.Logger = zapadapter.NewLogger(logger)
- cc.ConnConfig.LogLevel = pgx.LogLevelInfo
+ cc.ConnConfig.Logger = zapadapter.NewLogger(logger.Logger)
pgxPool, err := pgxpool.ConnectConfig(context.Background(), cc)
if err != nil {
diff --git a/server/swagger.yml b/server/swagger.yml
index c817b6dd..2eb01804 100644
--- a/server/swagger.yml
+++ b/server/swagger.yml
@@ -1,6 +1,6 @@
info:
title: Stencil server
- version: 0.1.0
+ version: 0.1.4
produces:
- application/json
consumes:
@@ -9,6 +9,8 @@ paths:
/ping:
get:
summary: service health check
+ tags:
+ - health
operationId: ping
responses:
"200":
@@ -21,7 +23,7 @@ paths:
produces:
- "application/json"
tags:
- - descriptors
+ - StencilService
parameters:
- name: "namespace"
in: "path"
@@ -65,51 +67,18 @@ paths:
type: "file"
responses:
"200":
- description: "Success response"
+ description: "Success response if operation succeded"
+ "400":
+ description: "Validation error response when user payload has missing required fields or currently being uploaded file is not backward compatible with previously uploaded file"
"409":
- description: "Conflict"
- get:
- summary: list all available descriptor names under one namespace
- tags:
- - descriptors
- parameters:
- - name: "namespace"
- in: "path"
- required: true
- type: "string"
- responses:
- "200":
- description: "returns list of descriptor names"
- schema:
- type: "array"
- items:
- type: string
- /v1/namespaces/{namespace}/descriptors/{name}/versions:
- get:
- summary: list all available versions for specified descriptor
- tags:
- - descriptors
- parameters:
- - name: "namespace"
- in: "path"
- required: true
- type: "string"
- - name: "name"
- in: "path"
- required: true
- type: "string"
- responses:
- "200":
- description: "returns list of versions"
- schema:
- type: "array"
- items:
- type: string
+ description: "conflict error reponse if namespace, name and version combination already present"
+ "500":
+ description: "Unexpected internal error reponse"
/v1/namespaces/{namespace}/descriptors/{name}/versions/{version}:
get:
summary: download specified descriptor file
tags:
- - descriptors
+ - StencilService
produces:
- application/octet-stream
parameters:
@@ -135,63 +104,109 @@ paths:
responses:
"200":
description: "download response"
- /v1/namespaces/{namespace}/metadata:
- post:
- summary: update metadata
- tags:
- - metadata
- parameters:
- - name: "namespace"
- in: "path"
- required: true
- type: "string"
- - name: "body"
- in: "body"
- description: "specify name and version in payload"
- required: true
- schema:
- $ref: "#/definitions/MetadataPayload"
- responses:
- "200":
- description: "Success response"
- /v1/namespaces/{namespace}/metadata/{name}:
+ /v1/snapshots:
get:
- summary: get latest version for specified descriptor
- tags:
- - metadata
+ operationId: StencilService_ListSnapshots
+ responses:
+ '200':
+ description: A successful response.
+ schema:
+ $ref: '#/definitions/v1ListSnapshotsResponse'
+ default:
+ description: An unexpected error response.
+ schema:
+ $ref: '#/definitions/rpcStatus'
parameters:
- - name: "namespace"
- in: "path"
- required: true
- type: "string"
- - name: "name"
- in: "path"
- required: true
- type: "string"
+ - name: namespace
+ in: query
+ required: false
+ type: string
+ - name: name
+ in: query
+ required: false
+ type: string
+ - name: version
+ in: query
+ required: false
+ type: string
+ - name: latest
+ in: query
+ required: false
+ type: boolean
+ tags:
+ - StencilService
+ /v1/snapshots/{id}/promote:
+ patch:
+ summary: PromoteSnapshot promotes particular snapshot version as latest
+ operationId: StencilService_PromoteSnapshot
responses:
- "200":
- description: "Success response"
+ '200':
+ description: A successful response.
schema:
- $ref: "#/definitions/MetadataResponse"
-
-tags:
- - name: "descriptors"
- description: "Manage descriptors"
- - name: "metadata"
- description: "manage latest versions for uploaded descriptor files"
+ $ref: '#/definitions/v1PromoteSnapshotResponse'
+ default:
+ description: An unexpected error response.
+ schema:
+ $ref: '#/definitions/rpcStatus'
+ parameters:
+ - name: id
+ in: path
+ required: true
+ type: string
+ format: int64
+ tags:
+ - StencilService
definitions:
- MetadataResponse:
+ protobufAny:
+ type: object
properties:
- version:
+ typeUrl:
+ type: string
+ value:
type: string
+ format: byte
+ rpcStatus:
type: object
- MetadataPayload:
properties:
+ code:
+ type: integer
+ format: int32
+ message:
+ type: string
+ details:
+ type: array
+ items:
+ $ref: '#/definitions/protobufAny'
+ v1ListSnapshotsResponse:
+ type: object
+ properties:
+ snapshots:
+ type: array
+ items:
+ $ref: '#/definitions/v1Snapshot'
+ v1PromoteSnapshotResponse:
+ type: object
+ properties:
+ snapshot:
+ $ref: '#/definitions/v1Snapshot'
+ v1Snapshot:
+ type: object
+ properties:
+ id:
+ type: string
+ format: int64
+ namespace:
+ type: string
+ required:
+ - namespace
name:
type: string
version:
type: string
- type: object
+ latest:
+ type: boolean
+ required:
+ - namespace
schemes:
- http
swagger: "2.0"