diff --git a/main.go b/main.go
index 4790345..1dc94a7 100644
--- a/main.go
+++ b/main.go
@@ -35,6 +35,9 @@ func main() {
func run(_ *cli.Context) error {
ctx := signals.SetupSignalHandler(context.Background())
debugconfig.MustSetupDebug()
- s := config.MustServer(ctx)
+ s, err := config.ToServer(ctx)
+ if err != nil {
+ return err
+ }
return s.ListenAndServe(ctx, config.HTTPSListenPort, config.HTTPListenPort, nil)
}
diff --git a/pkg/accesscontrol/access_control.go b/pkg/accesscontrol/access_control.go
index 7c19fbf..cc1b34e 100644
--- a/pkg/accesscontrol/access_control.go
+++ b/pkg/accesscontrol/access_control.go
@@ -1,10 +1,9 @@
package accesscontrol
import (
- "fmt"
-
- "github.com/rancher/steve/pkg/schemaserver/server"
- "github.com/rancher/steve/pkg/schemaserver/types"
+ "github.com/rancher/apiserver/pkg/server"
+ "github.com/rancher/apiserver/pkg/types"
+ "github.com/rancher/steve/pkg/attributes"
)
type AccessControl struct {
@@ -16,9 +15,11 @@ func NewAccessControl() *AccessControl {
}
func (a *AccessControl) CanWatch(apiOp *types.APIRequest, schema *types.APISchema) error {
- access := GetAccessListMap(schema)
- if _, ok := access["watch"]; ok {
- return nil
+ if attributes.GVK(schema).Kind != "" {
+ access := GetAccessListMap(schema)
+ if _, ok := access["watch"]; ok {
+ return nil
+ }
}
- return fmt.Errorf("watch not allowed")
+ return a.SchemaBasedAccess.CanWatch(apiOp, schema)
}
diff --git a/pkg/accesscontrol/access_set.go b/pkg/accesscontrol/access_set.go
index b221ea1..7597cf7 100644
--- a/pkg/accesscontrol/access_set.go
+++ b/pkg/accesscontrol/access_set.go
@@ -3,8 +3,8 @@ package accesscontrol
import (
"sort"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/attributes"
- "github.com/rancher/steve/pkg/schemaserver/types"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
)
diff --git a/pkg/attributes/attributes.go b/pkg/attributes/attributes.go
index f97550e..f07034b 100644
--- a/pkg/attributes/attributes.go
+++ b/pkg/attributes/attributes.go
@@ -3,7 +3,7 @@ package attributes
import (
"fmt"
- "github.com/rancher/steve/pkg/schemaserver/types"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/wrangler/pkg/data/convert"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
diff --git a/pkg/client/factory.go b/pkg/client/factory.go
index db8159e..f9119c4 100644
--- a/pkg/client/factory.go
+++ b/pkg/client/factory.go
@@ -5,8 +5,8 @@ import (
"net/http"
"time"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/attributes"
- "github.com/rancher/steve/pkg/schemaserver/types"
"k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
diff --git a/pkg/clustercache/controller.go b/pkg/clustercache/controller.go
index 0035b1f..48fc6dc 100644
--- a/pkg/clustercache/controller.go
+++ b/pkg/clustercache/controller.go
@@ -5,9 +5,9 @@ import (
"sync"
"time"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/attributes"
"github.com/rancher/steve/pkg/schema"
- "github.com/rancher/steve/pkg/schemaserver/types"
"github.com/rancher/wrangler/pkg/merr"
"github.com/rancher/wrangler/pkg/summary/client"
"github.com/rancher/wrangler/pkg/summary/informer"
diff --git a/pkg/controllers/schema/schemas.go b/pkg/controllers/schema/schemas.go
index 14bffd7..9364754 100644
--- a/pkg/controllers/schema/schemas.go
+++ b/pkg/controllers/schema/schemas.go
@@ -6,11 +6,11 @@ import (
"sync/atomic"
"time"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/attributes"
+ "github.com/rancher/steve/pkg/resources/common"
schema2 "github.com/rancher/steve/pkg/schema"
"github.com/rancher/steve/pkg/schema/converter"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/steve/pkg/server/resources/common"
apiextcontrollerv1beta1 "github.com/rancher/wrangler-api/pkg/generated/controllers/apiextensions.k8s.io/v1beta1"
v1 "github.com/rancher/wrangler-api/pkg/generated/controllers/apiregistration.k8s.io/v1"
"github.com/sirupsen/logrus"
diff --git a/pkg/dashboard/ui.go b/pkg/dashboard/ui.go
index 1d0c262..51d4c21 100644
--- a/pkg/dashboard/ui.go
+++ b/pkg/dashboard/ui.go
@@ -7,8 +7,8 @@ import (
"strings"
"github.com/gorilla/mux"
- "github.com/rancher/steve/pkg/responsewriter"
- "github.com/rancher/steve/pkg/schemaserver/parse"
+ "github.com/rancher/apiserver/pkg/middleware"
+ "github.com/rancher/apiserver/pkg/parse"
"github.com/sirupsen/logrus"
)
@@ -28,15 +28,17 @@ func content(uiSetting func() string) http.Handler {
}
func Route(next http.Handler, uiSetting func() string) http.Handler {
- uiContent := responsewriter.NewMiddlewareChain(responsewriter.Gzip,
- responsewriter.DenyFrameOptions,
- responsewriter.CacheMiddleware("json", "js", "css")).Handler(content(uiSetting))
+ uiContent := middleware.NewMiddlewareChain(middleware.Gzip,
+ middleware.DenyFrameOptions,
+ middleware.CacheMiddleware("json", "js", "css")).Handler(content(uiSetting))
root := mux.NewRouter()
root.UseEncodedPath()
+ root.Path("/").HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
+ http.Redirect(rw, req, "/dashboard/", http.StatusFound)
+ })
root.Path("/dashboard").HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- rw.Header().Add("Location", "/dashboard/")
- rw.WriteHeader(http.StatusFound)
+ http.Redirect(rw, req, "/dashboard/", http.StatusFound)
})
root.PathPrefix("/dashboard/assets").Handler(uiContent)
root.PathPrefix("/dashboard/translations").Handler(uiContent)
diff --git a/pkg/server/resources/apigroups/apigroup.go b/pkg/resources/apigroups/apigroup.go
similarity index 93%
rename from pkg/server/resources/apigroups/apigroup.go
rename to pkg/resources/apigroups/apigroup.go
index 5d0cc19..5bc0082 100644
--- a/pkg/server/resources/apigroups/apigroup.go
+++ b/pkg/resources/apigroups/apigroup.go
@@ -5,8 +5,8 @@ import (
"github.com/rancher/steve/pkg/schema"
- "github.com/rancher/steve/pkg/schemaserver/store/empty"
- "github.com/rancher/steve/pkg/schemaserver/types"
+ "github.com/rancher/apiserver/pkg/store/empty"
+ "github.com/rancher/apiserver/pkg/types"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/discovery"
)
diff --git a/pkg/server/resources/clusters/clusters.go b/pkg/resources/clusters/clusters.go
similarity index 93%
rename from pkg/server/resources/clusters/clusters.go
rename to pkg/resources/clusters/clusters.go
index e2a0135..6d41b3d 100644
--- a/pkg/server/resources/clusters/clusters.go
+++ b/pkg/resources/clusters/clusters.go
@@ -5,12 +5,12 @@ import (
"net/http"
"time"
+ "github.com/rancher/apiserver/pkg/store/empty"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/clustercache"
- "github.com/rancher/steve/pkg/schemaserver/store/empty"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/steve/pkg/server/store/proxy"
- "github.com/rancher/steve/pkg/server/store/switchschema"
- "github.com/rancher/steve/pkg/server/store/switchstore"
+ "github.com/rancher/steve/pkg/stores/proxy"
+ "github.com/rancher/steve/pkg/stores/switchschema"
+ "github.com/rancher/steve/pkg/stores/switchstore"
"github.com/rancher/wrangler/pkg/data"
"github.com/rancher/wrangler/pkg/schemas/validation"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/pkg/server/resources/clusters/shell.go b/pkg/resources/clusters/shell.go
similarity index 99%
rename from pkg/server/resources/clusters/shell.go
rename to pkg/resources/clusters/shell.go
index b54b0f5..82a6d25 100644
--- a/pkg/server/resources/clusters/shell.go
+++ b/pkg/resources/clusters/shell.go
@@ -7,7 +7,7 @@ import (
"net/http/httputil"
"time"
- "github.com/rancher/steve/pkg/server/store/proxy"
+ "github.com/rancher/steve/pkg/stores/proxy"
"github.com/rancher/wrangler/pkg/condition"
"github.com/rancher/wrangler/pkg/schemas/validation"
"github.com/sirupsen/logrus"
diff --git a/pkg/server/resources/common/dynamiccolumns.go b/pkg/resources/common/dynamiccolumns.go
similarity index 97%
rename from pkg/server/resources/common/dynamiccolumns.go
rename to pkg/resources/common/dynamiccolumns.go
index 2ca1acd..42c507f 100644
--- a/pkg/server/resources/common/dynamiccolumns.go
+++ b/pkg/resources/common/dynamiccolumns.go
@@ -4,8 +4,8 @@ import (
"context"
"fmt"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/attributes"
- "github.com/rancher/steve/pkg/schemaserver/types"
"github.com/rancher/wrangler/pkg/ratelimit"
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/pkg/server/resources/common/formatter.go b/pkg/resources/common/formatter.go
similarity index 93%
rename from pkg/server/resources/common/formatter.go
rename to pkg/resources/common/formatter.go
index b5564c2..d702284 100644
--- a/pkg/server/resources/common/formatter.go
+++ b/pkg/resources/common/formatter.go
@@ -3,10 +3,10 @@ package common
import (
"strings"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/accesscontrol"
"github.com/rancher/steve/pkg/schema"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/steve/pkg/server/store/proxy"
+ "github.com/rancher/steve/pkg/stores/proxy"
"github.com/rancher/wrangler/pkg/data"
"github.com/rancher/wrangler/pkg/summary"
"k8s.io/apimachinery/pkg/api/meta"
diff --git a/pkg/server/resources/counts/counts.go b/pkg/resources/counts/counts.go
similarity index 98%
rename from pkg/server/resources/counts/counts.go
rename to pkg/resources/counts/counts.go
index 50e274e..c57eb48 100644
--- a/pkg/server/resources/counts/counts.go
+++ b/pkg/resources/counts/counts.go
@@ -5,11 +5,11 @@ import (
"strconv"
"sync"
+ "github.com/rancher/apiserver/pkg/store/empty"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/accesscontrol"
"github.com/rancher/steve/pkg/attributes"
"github.com/rancher/steve/pkg/clustercache"
- "github.com/rancher/steve/pkg/schemaserver/store/empty"
- "github.com/rancher/steve/pkg/schemaserver/types"
"github.com/rancher/wrangler/pkg/summary"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
diff --git a/pkg/server/resources/helm/formatter.go b/pkg/resources/helm/formatter.go
similarity index 96%
rename from pkg/server/resources/helm/formatter.go
rename to pkg/resources/helm/formatter.go
index 29284fc..3d324f3 100644
--- a/pkg/server/resources/helm/formatter.go
+++ b/pkg/resources/helm/formatter.go
@@ -1,9 +1,9 @@
package helm
import (
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/attributes"
"github.com/rancher/steve/pkg/schema/converter"
- "github.com/rancher/steve/pkg/schemaserver/types"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
diff --git a/pkg/server/resources/helm/helm2.go b/pkg/resources/helm/helm2.go
similarity index 100%
rename from pkg/server/resources/helm/helm2.go
rename to pkg/resources/helm/helm2.go
diff --git a/pkg/server/resources/helm/helm3.go b/pkg/resources/helm/helm3.go
similarity index 100%
rename from pkg/server/resources/helm/helm3.go
rename to pkg/resources/helm/helm3.go
diff --git a/pkg/server/resources/helm/register.go b/pkg/resources/helm/register.go
similarity index 80%
rename from pkg/server/resources/helm/register.go
rename to pkg/resources/helm/register.go
index b3af89b..87c8d15 100644
--- a/pkg/server/resources/helm/register.go
+++ b/pkg/resources/helm/register.go
@@ -3,8 +3,8 @@ package helm
import (
"net/http"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/steve/pkg/server/store/partition"
+ "github.com/rancher/apiserver/pkg/types"
+ "github.com/rancher/steve/pkg/stores/partition"
)
func Register(schemas *types.APISchemas) {
diff --git a/pkg/server/resources/helm/release.go b/pkg/resources/helm/release.go
similarity index 100%
rename from pkg/server/resources/helm/release.go
rename to pkg/resources/helm/release.go
diff --git a/pkg/server/resources/helm/store.go b/pkg/resources/helm/store.go
similarity index 89%
rename from pkg/server/resources/helm/store.go
rename to pkg/resources/helm/store.go
index 9b0d08d..04a8535 100644
--- a/pkg/server/resources/helm/store.go
+++ b/pkg/resources/helm/store.go
@@ -3,11 +3,11 @@ package helm
import (
"strings"
- "github.com/rancher/steve/pkg/schemaserver/store/empty"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/steve/pkg/server/store/partition"
- "github.com/rancher/steve/pkg/server/store/selector"
- "github.com/rancher/steve/pkg/server/store/switchschema"
+ "github.com/rancher/apiserver/pkg/store/empty"
+ "github.com/rancher/apiserver/pkg/types"
+ "github.com/rancher/steve/pkg/stores/partition"
+ "github.com/rancher/steve/pkg/stores/selector"
+ "github.com/rancher/steve/pkg/stores/switchschema"
"github.com/rancher/wrangler/pkg/schemas/validation"
"k8s.io/apimachinery/pkg/labels"
)
diff --git a/pkg/server/resources/helm/types.go b/pkg/resources/helm/types.go
similarity index 100%
rename from pkg/server/resources/helm/types.go
rename to pkg/resources/helm/types.go
diff --git a/pkg/server/resources/schema.go b/pkg/resources/schema.go
similarity index 62%
rename from pkg/server/resources/schema.go
rename to pkg/resources/schema.go
index d7f3738..355c000 100644
--- a/pkg/server/resources/schema.go
+++ b/pkg/resources/schema.go
@@ -3,27 +3,27 @@ package resources
import (
"context"
+ "github.com/rancher/apiserver/pkg/store/apiroot"
+ "github.com/rancher/apiserver/pkg/subscribe"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/accesscontrol"
"github.com/rancher/steve/pkg/client"
"github.com/rancher/steve/pkg/clustercache"
+ "github.com/rancher/steve/pkg/resources/apigroups"
+ "github.com/rancher/steve/pkg/resources/clusters"
+ "github.com/rancher/steve/pkg/resources/common"
+ "github.com/rancher/steve/pkg/resources/counts"
+ "github.com/rancher/steve/pkg/resources/helm"
+ "github.com/rancher/steve/pkg/resources/userpreferences"
"github.com/rancher/steve/pkg/schema"
- "github.com/rancher/steve/pkg/schemaserver/store/apiroot"
- "github.com/rancher/steve/pkg/schemaserver/subscribe"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/steve/pkg/server/resources/apigroups"
- "github.com/rancher/steve/pkg/server/resources/clusters"
- "github.com/rancher/steve/pkg/server/resources/common"
- "github.com/rancher/steve/pkg/server/resources/counts"
- "github.com/rancher/steve/pkg/server/resources/helm"
- "github.com/rancher/steve/pkg/server/resources/userpreferences"
- "github.com/rancher/steve/pkg/server/store/proxy"
+ "github.com/rancher/steve/pkg/stores/proxy"
"k8s.io/client-go/discovery"
)
func DefaultSchemas(ctx context.Context, baseSchema *types.APISchemas, ccache clustercache.ClusterCache, cg proxy.ClientGetter) (*types.APISchemas, error) {
counts.Register(baseSchema, ccache)
subscribe.Register(baseSchema)
- apiroot.Register(baseSchema, []string{"v1"}, []string{"proxy:/apis"})
+ apiroot.Register(baseSchema, []string{"v1"}, "proxy:/apis")
userpreferences.Register(baseSchema, cg)
helm.Register(baseSchema)
diff --git a/pkg/server/resources/schemas/template.go b/pkg/resources/schemas/template.go
similarity index 95%
rename from pkg/server/resources/schemas/template.go
rename to pkg/resources/schemas/template.go
index 7515eea..b32b2c5 100644
--- a/pkg/server/resources/schemas/template.go
+++ b/pkg/resources/schemas/template.go
@@ -5,12 +5,12 @@ import (
"sync"
"time"
- "github.com/rancher/steve/pkg/schemaserver/builtin"
+ "github.com/rancher/apiserver/pkg/builtin"
+ schemastore "github.com/rancher/apiserver/pkg/store/schema"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/accesscontrol"
"github.com/rancher/steve/pkg/schema"
- schemastore "github.com/rancher/steve/pkg/schemaserver/store/schema"
- "github.com/rancher/steve/pkg/schemaserver/types"
"github.com/rancher/wrangler/pkg/broadcast"
"github.com/rancher/wrangler/pkg/schemas/validation"
"github.com/sirupsen/logrus"
diff --git a/pkg/server/resources/userpreferences/configmap.go b/pkg/resources/userpreferences/configmap.go
similarity index 94%
rename from pkg/server/resources/userpreferences/configmap.go
rename to pkg/resources/userpreferences/configmap.go
index e19865b..f9b4366 100644
--- a/pkg/server/resources/userpreferences/configmap.go
+++ b/pkg/resources/userpreferences/configmap.go
@@ -1,10 +1,10 @@
package userpreferences
import (
+ "github.com/rancher/apiserver/pkg/store/empty"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/norman/types/convert"
- "github.com/rancher/steve/pkg/schemaserver/store/empty"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/steve/pkg/server/store/proxy"
+ "github.com/rancher/steve/pkg/stores/proxy"
"github.com/rancher/wrangler/pkg/schemas/validation"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
diff --git a/pkg/server/resources/userpreferences/rancherpref.go b/pkg/resources/userpreferences/rancherpref.go
similarity index 96%
rename from pkg/server/resources/userpreferences/rancherpref.go
rename to pkg/resources/userpreferences/rancherpref.go
index 14fd1a8..d809c84 100644
--- a/pkg/server/resources/userpreferences/rancherpref.go
+++ b/pkg/resources/userpreferences/rancherpref.go
@@ -1,10 +1,10 @@
package userpreferences
import (
+ "github.com/rancher/apiserver/pkg/store/empty"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/attributes"
- "github.com/rancher/steve/pkg/schemaserver/store/empty"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/steve/pkg/server/store/proxy"
+ "github.com/rancher/steve/pkg/stores/proxy"
"github.com/rancher/wrangler/pkg/data/convert"
"github.com/rancher/wrangler/pkg/schemas/validation"
apierrors "k8s.io/apimachinery/pkg/api/errors"
diff --git a/pkg/server/resources/userpreferences/userpreferences.go b/pkg/resources/userpreferences/userpreferences.go
similarity index 93%
rename from pkg/server/resources/userpreferences/userpreferences.go
rename to pkg/resources/userpreferences/userpreferences.go
index a4c267a..716b476 100644
--- a/pkg/server/resources/userpreferences/userpreferences.go
+++ b/pkg/resources/userpreferences/userpreferences.go
@@ -3,9 +3,9 @@ package userpreferences
import (
"net/http"
- "github.com/rancher/steve/pkg/schemaserver/store/empty"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/steve/pkg/server/store/proxy"
+ "github.com/rancher/apiserver/pkg/store/empty"
+ "github.com/rancher/apiserver/pkg/types"
+ "github.com/rancher/steve/pkg/stores/proxy"
"github.com/rancher/wrangler/pkg/name"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/endpoints/request"
diff --git a/pkg/responsewriter/cache.go b/pkg/responsewriter/cache.go
deleted file mode 100644
index e5ece3c..0000000
--- a/pkg/responsewriter/cache.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package responsewriter
-
-import (
- "net/http"
- "strings"
-
- "github.com/gorilla/mux"
-)
-
-func CacheMiddleware(suffixes ...string) mux.MiddlewareFunc {
- return mux.MiddlewareFunc(func(handler http.Handler) http.Handler {
- return Cache(handler, suffixes...)
- })
-}
-
-func Cache(handler http.Handler, suffixes ...string) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- i := strings.LastIndex(r.URL.Path, ".")
- if i >= 0 {
- for _, suffix := range suffixes {
- if suffix == r.URL.Path[i+1:] {
- w.Header().Set("Cache-Control", "max-age=31536000, public")
- }
- }
- }
- handler.ServeHTTP(w, r)
- })
-}
-
-func NoCache(handler http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
- handler.ServeHTTP(w, r)
- })
-}
-
-func DenyFrameOptions(handler http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("X-Frame-Options", "deny")
- handler.ServeHTTP(w, r)
- })
-}
-
-func ContentTypeOptions(handler http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("X-Content-Type-Options", "nosniff")
- handler.ServeHTTP(w, r)
- })
-}
diff --git a/pkg/responsewriter/content.go b/pkg/responsewriter/content.go
deleted file mode 100644
index 101d4f8..0000000
--- a/pkg/responsewriter/content.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package responsewriter
-
-import (
- "bufio"
- "fmt"
- "net"
- "net/http"
- "reflect"
- "strings"
-)
-
-type ContentTypeWriter struct {
- http.ResponseWriter
-}
-
-func (c ContentTypeWriter) Write(b []byte) (int, error) {
- found := false
- for k := range c.Header() {
- if strings.EqualFold(k, "Content-Type") {
- found = true
- break
- }
- }
- if !found {
- c.Header().Set("Content-Type", http.DetectContentType(b))
- }
- return c.ResponseWriter.Write(b)
-}
-
-func ContentType(handler http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- writer := ContentTypeWriter{ResponseWriter: w}
- handler.ServeHTTP(writer, r)
- })
-}
-
-func (c ContentTypeWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
- if hijacker, ok := c.ResponseWriter.(http.Hijacker); ok {
- return hijacker.Hijack()
- }
- return nil, nil, fmt.Errorf("Upstream ResponseWriter of type %v does not implement http.Hijacker", reflect.TypeOf(c.ResponseWriter))
-}
diff --git a/pkg/responsewriter/gzip.go b/pkg/responsewriter/gzip.go
deleted file mode 100644
index 31ca8c1..0000000
--- a/pkg/responsewriter/gzip.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package responsewriter
-
-import (
- "bufio"
- "compress/gzip"
- "fmt"
- "io"
- "net"
- "net/http"
- "reflect"
- "strings"
-)
-
-type wrapWriter struct {
- gzipResponseWriter
-
- code int
-}
-
-type gzipResponseWriter struct {
- io.Writer
- http.ResponseWriter
-}
-
-func (g gzipResponseWriter) Write(b []byte) (int, error) {
- // Header logic is kept here in case the user does not use WriteHeader
- g.Header().Set("Content-Encoding", "gzip")
- g.Header().Del("Content-Length")
-
- return g.Writer.Write(b)
-}
-
-// Close uses gzip to write gzip footer if message is gzip encoded
-func (g gzipResponseWriter) Close(writer *gzip.Writer) {
- if g.Header().Get("Content-Encoding") == "gzip" {
- writer.Close()
- }
-}
-
-// WriteHeader sets gzip encoding and removes length. Should always be used when using gzip writer.
-func (g gzipResponseWriter) WriteHeader(statusCode int) {
- g.Header().Set("Content-Encoding", "gzip")
- g.Header().Del("Content-Length")
- g.ResponseWriter.WriteHeader(statusCode)
-}
-
-// Gzip creates a gzip writer if gzip encoding is accepted.
-func Gzip(handler http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
- handler.ServeHTTP(w, r)
- return
- }
- gz := gzip.NewWriter(w)
-
- gzw := &wrapWriter{gzipResponseWriter{Writer: gz, ResponseWriter: w}, http.StatusOK}
- defer gzw.Close(gz)
-
- // Content encoding will be set once Write or WriteHeader is called, to avoid gzipping empty messages
- handler.ServeHTTP(gzw, r)
- })
-}
-
-// Hijack must be implemented to properly chain with handlers expecting a hijacker handler to be passed
-func (g *gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
- if hijacker, ok := g.ResponseWriter.(http.Hijacker); ok {
- return hijacker.Hijack()
- }
- return nil, nil, fmt.Errorf("Upstream ResponseWriter of type %v does not implement http.Hijacker", reflect.TypeOf(g.ResponseWriter))
-}
diff --git a/pkg/responsewriter/gzip_test.go b/pkg/responsewriter/gzip_test.go
deleted file mode 100644
index 3e13f7c..0000000
--- a/pkg/responsewriter/gzip_test.go
+++ /dev/null
@@ -1,174 +0,0 @@
-package responsewriter
-
-import (
- "compress/gzip"
- "net/http"
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-// All other writers will attempt additional unnecessary logic
-// Implements http.responseWriter and io.Writer
-type DummyWriter struct {
- header map[string][]string
- buffer []byte
-}
-
-type DummyHandler struct {
-}
-
-type DummyHandlerWithWrite struct {
- DummyHandler
- next http.Handler
-}
-
-func NewDummyWriter() *DummyWriter {
- return &DummyWriter{map[string][]string{}, []byte{}}
-}
-
-func NewRequest(accept string) *http.Request {
- return &http.Request{
- Header: map[string][]string{"Accept-Encoding": {accept}},
- }
-}
-
-func (d *DummyWriter) Header() http.Header {
- return d.header
-}
-
-func (d *DummyWriter) Write(p []byte) (n int, err error) {
- d.buffer = append(d.buffer, p...)
- return 0, nil
-}
-
-func (d *DummyWriter) WriteHeader(int) {
-}
-
-func (d *DummyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-}
-
-func (d *DummyHandlerWithWrite) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- w.Write([]byte{0, 0})
- if d.next != nil {
- d.next.ServeHTTP(w, r)
- }
-}
-
-// TestWriteHeader asserts content-length header is deleted and content-encoding header is set to gzip
-func TestWriteHeader(t *testing.T) {
- assert := assert.New(t)
-
- w := NewDummyWriter()
- gz := &gzipResponseWriter{gzip.NewWriter(w), w}
-
- gz.Header().Set("Content-Length", "80")
- gz.WriteHeader(400)
- // Content-Length should have been deleted in WriterHeader, resulting in empty string
- assert.Equal("", gz.Header().Get("Content-Length"))
- assert.Equal(1, len(w.header["Content-Encoding"]))
- assert.Equal("gzip", gz.Header().Get("Content-Encoding"))
-}
-
-// TestSetContentWithoutWrite asserts content-encoding is NOT "gzip" if accept-encoding header does not contain gzip
-func TestSetContentWithoutWrite(t *testing.T) {
- assert := assert.New(t)
-
- // Test content encoding header when write is not used
- handlerFunc := Gzip(&DummyHandler{})
-
- // Test when accept-encoding only contains gzip
- rw := NewDummyWriter()
- req := NewRequest("gzip")
- handlerFunc.ServeHTTP(rw, req)
- // Content encoding should be empty since write has not been used
- assert.Equal(0, len(rw.header["Content-Encoding"]))
- assert.Equal("", rw.Header().Get("Content-Encoding"))
-
- // Test when accept-encoding contains multiple options, including gzip
- rw = NewDummyWriter()
- req = NewRequest("json, xml, gzip")
- handlerFunc.ServeHTTP(rw, req)
- assert.Equal(0, len(rw.header["Content-Encoding"]))
- assert.Equal("", rw.Header().Get("Content-Encoding"))
-
- // Test when accept-encoding is empty
- req = NewRequest("")
- rw = NewDummyWriter()
- handlerFunc.ServeHTTP(rw, req)
- assert.Equal(0, len(rw.header["Content-Encoding"]))
- assert.Equal("", rw.Header().Get("Content-Encoding"))
-
- // Test when accept-encoding is is not empty but does not include gzip
- req = NewRequest("json, xml")
- rw = NewDummyWriter()
- handlerFunc.ServeHTTP(rw, req)
- assert.Equal(0, len(rw.header["Content-Encoding"]))
- assert.Equal("", rw.Header().Get("Content-Encoding"))
-}
-
-// TestSetContentWithWrite asserts content-encoding is "gzip" if accept-encoding header contains gzip
-func TestSetContentWithWrite(t *testing.T) {
- assert := assert.New(t)
-
- // Test content encoding header when write is used
- handlerFunc := Gzip(&DummyHandlerWithWrite{})
-
- // Test when accept-encoding only contains gzip
- req := NewRequest("gzip")
- rw := NewDummyWriter()
- handlerFunc.ServeHTTP(rw, req)
- // Content encoding should be gzip since write has been used
- assert.Equal(1, len(rw.header["Content-Encoding"]))
- assert.Equal("gzip", rw.Header().Get("Content-Encoding"))
-
- // Test when accept-encoding contains multiple options, including gzip
- req = NewRequest("json, xml, gzip")
- rw = NewDummyWriter()
- handlerFunc.ServeHTTP(rw, req)
- // Content encoding should be gzip since write has been used
- assert.Equal(1, len(rw.header["Content-Encoding"]))
- assert.Equal("gzip", rw.Header().Get("Content-Encoding"))
-
- // Test when accept-encoding is empty
- req = NewRequest("")
- rw = NewDummyWriter()
- handlerFunc.ServeHTTP(rw, req)
- // Content encoding should be empty since gzip is not an accepted encoding
- assert.Equal(0, len(rw.header["Content-Encoding"]))
- assert.Equal("", rw.Header().Get("Content-Encoding"))
-
- // Test when accept-encoding is is not empty but does not include gzip
- req = NewRequest("json, xml")
- rw = NewDummyWriter()
- handlerFunc.ServeHTTP(rw, req)
- // Content encoding should be empty since gzip is not an accepted encoding
- assert.Equal(0, len(rw.header["Content-Encoding"]))
- assert.Equal("", rw.Header().Get("Content-Encoding"))
-}
-
-// TestMultipleWrites ensures that Write can be used multiple times
-func TestMultipleWrites(t *testing.T) {
- assert := assert.New(t)
-
- // Handler function that contains one writing handler
- handlerFuncOneWrite := Gzip(&DummyHandlerWithWrite{})
-
- // Handler function that contains a chain of two writing handlers
- handlerFuncTwoWrites := Gzip(&DummyHandlerWithWrite{next: &DummyHandlerWithWrite{}})
-
- req := NewRequest("gzip")
- rw := NewDummyWriter()
- handlerFuncOneWrite.ServeHTTP(rw, req)
- oneWriteResult := rw.buffer
-
- req = NewRequest("gzip")
- rw = NewDummyWriter()
- handlerFuncTwoWrites.ServeHTTP(rw, req)
- multiWriteResult := rw.buffer
-
- // Content encoding should be gzip since write has been used (twice)
- assert.Equal(1, len(rw.header["Content-Encoding"]))
- assert.Equal("gzip", rw.Header().Get("Content-Encoding"))
- assert.NotEqual(multiWriteResult, oneWriteResult)
-}
diff --git a/pkg/responsewriter/middleware.go b/pkg/responsewriter/middleware.go
deleted file mode 100644
index f8f2b7e..0000000
--- a/pkg/responsewriter/middleware.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package responsewriter
-
-import (
- "net/http"
-
- "github.com/gorilla/mux"
-)
-
-type MiddlewareChain struct {
- middleWares []mux.MiddlewareFunc
-}
-
-func NewMiddlewareChain(middleWares ...mux.MiddlewareFunc) *MiddlewareChain {
- return &MiddlewareChain{middleWares: middleWares}
-}
-
-func (m *MiddlewareChain) Handler(handler http.Handler) http.Handler {
- rtn := handler
- for i := len(m.middleWares) - 1; i >= 0; i-- {
- w := m.middleWares[i]
- rtn = w.Middleware(rtn)
- }
- return rtn
-}
diff --git a/pkg/schema/collection.go b/pkg/schema/collection.go
index ce0324e..2427254 100644
--- a/pkg/schema/collection.go
+++ b/pkg/schema/collection.go
@@ -6,10 +6,10 @@ import (
"strings"
"sync"
+ "github.com/rancher/apiserver/pkg/server"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/accesscontrol"
"github.com/rancher/steve/pkg/attributes"
- "github.com/rancher/steve/pkg/schemaserver/server"
- "github.com/rancher/steve/pkg/schemaserver/types"
"github.com/rancher/wrangler/pkg/name"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/runtime/schema"
diff --git a/pkg/schema/converter/crd.go b/pkg/schema/converter/crd.go
index 492bf21..d0ea92a 100644
--- a/pkg/schema/converter/crd.go
+++ b/pkg/schema/converter/crd.go
@@ -1,9 +1,9 @@
package converter
import (
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/attributes"
"github.com/rancher/steve/pkg/schema/table"
- "github.com/rancher/steve/pkg/schemaserver/types"
"github.com/rancher/wrangler-api/pkg/generated/controllers/apiextensions.k8s.io/v1beta1"
"github.com/rancher/wrangler/pkg/schemas"
beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
diff --git a/pkg/schema/converter/discovery.go b/pkg/schema/converter/discovery.go
index c23da18..98bf3bf 100644
--- a/pkg/schema/converter/discovery.go
+++ b/pkg/schema/converter/discovery.go
@@ -3,8 +3,8 @@ package converter
import (
"strings"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/attributes"
- "github.com/rancher/steve/pkg/schemaserver/types"
"github.com/rancher/wrangler/pkg/merr"
"github.com/rancher/wrangler/pkg/schemas"
"github.com/sirupsen/logrus"
diff --git a/pkg/schema/converter/k8stonorman.go b/pkg/schema/converter/k8stonorman.go
index a1a5f54..6fd3977 100644
--- a/pkg/schema/converter/k8stonorman.go
+++ b/pkg/schema/converter/k8stonorman.go
@@ -4,7 +4,7 @@ import (
"fmt"
"strings"
- "github.com/rancher/steve/pkg/schemaserver/types"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/wrangler-api/pkg/generated/controllers/apiextensions.k8s.io/v1beta1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
diff --git a/pkg/schema/converter/openapi.go b/pkg/schema/converter/openapi.go
index 76bd5da..e2b0124 100644
--- a/pkg/schema/converter/openapi.go
+++ b/pkg/schema/converter/openapi.go
@@ -1,8 +1,8 @@
package converter
import (
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/attributes"
- "github.com/rancher/steve/pkg/schemaserver/types"
"github.com/rancher/wrangler/pkg/data/convert"
"github.com/rancher/wrangler/pkg/schemas"
"github.com/sirupsen/logrus"
diff --git a/pkg/schema/converter/openapiv3.go b/pkg/schema/converter/openapiv3.go
index d5b15a8..451bd49 100644
--- a/pkg/schema/converter/openapiv3.go
+++ b/pkg/schema/converter/openapiv3.go
@@ -1,7 +1,7 @@
package converter
import (
- "github.com/rancher/steve/pkg/schemaserver/types"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/wrangler/pkg/schemas"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
)
diff --git a/pkg/schema/factory.go b/pkg/schema/factory.go
index 7e1263f..24d6f9d 100644
--- a/pkg/schema/factory.go
+++ b/pkg/schema/factory.go
@@ -5,10 +5,10 @@ import (
"net/http"
"time"
+ "github.com/rancher/apiserver/pkg/builtin"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/accesscontrol"
"github.com/rancher/steve/pkg/attributes"
- "github.com/rancher/steve/pkg/schemaserver/builtin"
- "github.com/rancher/steve/pkg/schemaserver/types"
"k8s.io/apiserver/pkg/authentication/user"
)
diff --git a/pkg/schema/table/mapper.go b/pkg/schema/table/mapper.go
index b73f822..64d4da3 100644
--- a/pkg/schema/table/mapper.go
+++ b/pkg/schema/table/mapper.go
@@ -1,8 +1,8 @@
package table
import (
+ types2 "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/attributes"
- types2 "github.com/rancher/steve/pkg/schemaserver/types"
"github.com/rancher/wrangler/pkg/data"
types "github.com/rancher/wrangler/pkg/schemas"
"github.com/rancher/wrangler/pkg/schemas/mappers"
diff --git a/pkg/schemaserver/builtin/schema.go b/pkg/schemaserver/builtin/schema.go
deleted file mode 100644
index 3bb9f22..0000000
--- a/pkg/schemaserver/builtin/schema.go
+++ /dev/null
@@ -1,88 +0,0 @@
-package builtin
-
-import (
- "net/http"
-
- "github.com/rancher/steve/pkg/schemaserver/store/schema"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/wrangler/pkg/schemas"
- "github.com/rancher/wrangler/pkg/slice"
-)
-
-var (
- Schema = types.APISchema{
- Schema: &schemas.Schema{
- ID: "schema",
- PluralName: "schemas",
- CollectionMethods: []string{"GET"},
- ResourceMethods: []string{"GET"},
- ResourceFields: map[string]schemas.Field{
- "collectionActions": {Type: "map[json]"},
- "collectionFields": {Type: "map[json]"},
- "collectionFilters": {Type: "map[json]"},
- "collectionMethods": {Type: "array[string]"},
- "pluralName": {Type: "string"},
- "resourceActions": {Type: "map[json]"},
- "attributes": {Type: "map[json]"},
- "resourceFields": {Type: "map[json]"},
- "resourceMethods": {Type: "array[string]"},
- "version": {Type: "map[json]"},
- },
- },
- Formatter: SchemaFormatter,
- Store: schema.NewSchemaStore(),
- }
-
- Error = types.APISchema{
- Schema: &schemas.Schema{
- ID: "error",
- ResourceMethods: []string{},
- CollectionMethods: []string{},
- ResourceFields: map[string]schemas.Field{
- "code": {Type: "string"},
- "detail": {Type: "string", Nullable: true},
- "message": {Type: "string", Nullable: true},
- "fieldName": {Type: "string", Nullable: true},
- "status": {Type: "int"},
- },
- },
- }
-
- Collection = types.APISchema{
- Schema: &schemas.Schema{
- ID: "collection",
- ResourceMethods: []string{},
- CollectionMethods: []string{},
- ResourceFields: map[string]schemas.Field{
- "data": {Type: "array[json]"},
- "pagination": {Type: "map[json]"},
- "sort": {Type: "map[json]"},
- "filters": {Type: "map[json]"},
- },
- },
- }
-
- Schemas = types.EmptyAPISchemas().
- MustAddSchema(Schema).
- MustAddSchema(Error).
- MustAddSchema(Collection)
-)
-
-func SchemaFormatter(apiOp *types.APIRequest, resource *types.RawResource) {
- schema := apiOp.Schemas.LookupSchema(resource.ID)
- if schema == nil {
- return
- }
-
- collectionLink := getSchemaCollectionLink(apiOp, schema)
- if collectionLink != "" {
- resource.Links["collection"] = collectionLink
- }
-}
-
-func getSchemaCollectionLink(apiOp *types.APIRequest, schema *types.APISchema) string {
- if schema != nil && slice.ContainsString(schema.CollectionMethods, http.MethodGet) {
- return apiOp.URLBuilder.Collection(schema)
- }
- return ""
-}
diff --git a/pkg/schemaserver/handlers/create.go b/pkg/schemaserver/handlers/create.go
deleted file mode 100644
index c992b55..0000000
--- a/pkg/schemaserver/handlers/create.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package handlers
-
-import (
- "github.com/rancher/steve/pkg/schemaserver/httperror"
- "github.com/rancher/steve/pkg/schemaserver/parse"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/wrangler/pkg/schemas/validation"
-)
-
-func CreateHandler(apiOp *types.APIRequest) (types.APIObject, error) {
- var err error
-
- if err := apiOp.AccessControl.CanCreate(apiOp, apiOp.Schema); err != nil {
- return types.APIObject{}, err
- }
-
- data, err := parse.Body(apiOp.Request)
- if err != nil {
- return types.APIObject{}, err
- }
-
- store := apiOp.Schema.Store
- if store == nil {
- return types.APIObject{}, httperror.NewAPIError(validation.NotFound, "no store found")
- }
-
- data, err = store.Create(apiOp, apiOp.Schema, data)
- if err != nil {
- return types.APIObject{}, err
- }
-
- return data, nil
-}
diff --git a/pkg/schemaserver/handlers/delete.go b/pkg/schemaserver/handlers/delete.go
deleted file mode 100644
index 2ec787e..0000000
--- a/pkg/schemaserver/handlers/delete.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package handlers
-
-import (
- "github.com/rancher/steve/pkg/schemaserver/httperror"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/wrangler/pkg/schemas/validation"
-)
-
-func DeleteHandler(request *types.APIRequest) (types.APIObject, error) {
- if err := request.AccessControl.CanDelete(request, types.APIObject{}, request.Schema); err != nil {
- return types.APIObject{}, err
- }
-
- store := request.Schema.Store
- if store == nil {
- return types.APIObject{}, httperror.NewAPIError(validation.NotFound, "no store found")
- }
-
- return store.Delete(request, request.Schema, request.Name)
-}
diff --git a/pkg/schemaserver/handlers/error.go b/pkg/schemaserver/handlers/error.go
deleted file mode 100644
index ed72f4a..0000000
--- a/pkg/schemaserver/handlers/error.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package handlers
-
-import (
- "net/http"
- "net/url"
-
- "github.com/rancher/steve/pkg/schemaserver/httperror"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/wrangler/pkg/schemas/validation"
- "github.com/sirupsen/logrus"
-)
-
-func ErrorHandler(request *types.APIRequest, err error) {
- if err == validation.ErrComplete {
- return
- }
-
- if ec, ok := err.(validation.ErrorCode); ok {
- err = httperror.NewAPIError(ec, "")
- }
-
- var error *httperror.APIError
- if apiError, ok := err.(*httperror.APIError); ok {
- if apiError.Cause != nil {
- url, _ := url.PathUnescape(request.Request.URL.String())
- if url == "" {
- url = request.Request.URL.String()
- }
- logrus.Errorf("API error response %v for %v %v. Cause: %v", apiError.Code.Status, request.Request.Method,
- url, apiError.Cause)
- }
- error = apiError
- } else {
- logrus.Errorf("Unknown error: %v", err)
- error = &httperror.APIError{
- Code: validation.ServerError,
- Message: err.Error(),
- }
- }
-
- if error.Code.Status == http.StatusNoContent {
- request.Response.WriteHeader(http.StatusNoContent)
- return
- }
-
- data := toError(error)
- request.WriteResponse(error.Code.Status, data)
-}
-
-func toError(apiError *httperror.APIError) types.APIObject {
- e := map[string]interface{}{
- "type": "error",
- "status": apiError.Code.Status,
- "code": apiError.Code.Code,
- "message": apiError.Message,
- }
- if apiError.FieldName != "" {
- e["fieldName"] = apiError.FieldName
- }
-
- return types.APIObject{
- Type: "error",
- Object: e,
- }
-}
diff --git a/pkg/schemaserver/handlers/list.go b/pkg/schemaserver/handlers/list.go
deleted file mode 100644
index fc4c6b6..0000000
--- a/pkg/schemaserver/handlers/list.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package handlers
-
-import (
- "github.com/rancher/steve/pkg/schemaserver/httperror"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/wrangler/pkg/schemas/validation"
-)
-
-func ByIDHandler(request *types.APIRequest) (types.APIObject, error) {
- if err := request.AccessControl.CanGet(request, request.Schema); err != nil {
- return types.APIObject{}, err
- }
-
- store := request.Schema.Store
- if store == nil {
- return types.APIObject{}, httperror.NewAPIError(validation.NotFound, "no store found")
- }
-
- resp, err := store.ByID(request, request.Schema, request.Name)
- if err != nil {
- return resp, err
- }
-
- if request.Link != "" {
- if handler, ok := request.Schema.LinkHandlers[request.Link]; ok {
- handler.ServeHTTP(request.Response, request.Request)
- return types.APIObject{}, validation.ErrComplete
- }
- }
-
- return resp, nil
-}
-
-func ListHandler(request *types.APIRequest) (types.APIObjectList, error) {
- if request.Name == "" {
- if err := request.AccessControl.CanList(request, request.Schema); err != nil {
- return types.APIObjectList{}, err
- }
- } else {
- if err := request.AccessControl.CanGet(request, request.Schema); err != nil {
- return types.APIObjectList{}, err
- }
- }
-
- store := request.Schema.Store
- if store == nil {
- return types.APIObjectList{}, httperror.NewAPIError(validation.NotFound, "no store found")
- }
-
- return store.List(request, request.Schema)
-}
diff --git a/pkg/schemaserver/handlers/update.go b/pkg/schemaserver/handlers/update.go
deleted file mode 100644
index 4831ab7..0000000
--- a/pkg/schemaserver/handlers/update.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package handlers
-
-import (
- "net/http"
-
- "github.com/rancher/steve/pkg/schemaserver/httperror"
- "github.com/rancher/steve/pkg/schemaserver/parse"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/wrangler/pkg/schemas/validation"
-)
-
-func UpdateHandler(apiOp *types.APIRequest) (types.APIObject, error) {
- if err := apiOp.AccessControl.CanUpdate(apiOp, types.APIObject{}, apiOp.Schema); err != nil {
- return types.APIObject{}, err
- }
-
- var (
- data types.APIObject
- err error
- )
- if apiOp.Method != http.MethodPatch {
- data, err = parse.Body(apiOp.Request)
- if err != nil {
- return types.APIObject{}, err
- }
- }
-
- store := apiOp.Schema.Store
- if store == nil {
- return types.APIObject{}, httperror.NewAPIError(validation.NotFound, "no store found")
- }
-
- data, err = store.Update(apiOp, apiOp.Schema, data, apiOp.Name)
- if err != nil {
- return types.APIObject{}, err
- }
-
- return data, nil
-}
diff --git a/pkg/schemaserver/httperror/error.go b/pkg/schemaserver/httperror/error.go
deleted file mode 100644
index 7fefdd1..0000000
--- a/pkg/schemaserver/httperror/error.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package httperror
-
-import (
- "fmt"
-
- "github.com/rancher/wrangler/pkg/schemas/validation"
-)
-
-type APIError struct {
- Code validation.ErrorCode
- Message string
- Cause error
- FieldName string
-}
-
-func NewAPIError(code validation.ErrorCode, message string) error {
- return &APIError{
- Code: code,
- Message: message,
- }
-}
-
-func NewFieldAPIError(code validation.ErrorCode, fieldName, message string) error {
- return &APIError{
- Code: code,
- Message: message,
- FieldName: fieldName,
- }
-}
-
-// WrapFieldAPIError will cause the API framework to log the underlying err before returning the APIError as a response.
-// err WILL NOT be in the API response
-func WrapFieldAPIError(err error, code validation.ErrorCode, fieldName, message string) error {
- return &APIError{
- Cause: err,
- Code: code,
- Message: message,
- FieldName: fieldName,
- }
-}
-
-// WrapAPIError will cause the API framework to log the underlying err before returning the APIError as a response.
-// err WILL NOT be in the API response
-func WrapAPIError(err error, code validation.ErrorCode, message string) error {
- return &APIError{
- Code: code,
- Message: message,
- Cause: err,
- }
-}
-
-func (a *APIError) Error() string {
- if a.FieldName != "" {
- return fmt.Sprintf("%s=%s: %s", a.FieldName, a.Code, a.Message)
- }
- return fmt.Sprintf("%s: %s", a.Code, a.Message)
-}
-
-func IsAPIError(err error) bool {
- _, ok := err.(*APIError)
- return ok
-}
-
-func IsConflict(err error) bool {
- if apiError, ok := err.(*APIError); ok {
- return apiError.Code.Status == 409
- }
-
- return false
-}
diff --git a/pkg/schemaserver/parse/browser.go b/pkg/schemaserver/parse/browser.go
deleted file mode 100644
index 6d195d0..0000000
--- a/pkg/schemaserver/parse/browser.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package parse
-
-import (
- "net/http"
- "strings"
-)
-
-func IsBrowser(req *http.Request, checkAccepts bool) bool {
- accepts := strings.ToLower(req.Header.Get("Accept"))
- userAgent := strings.ToLower(req.Header.Get("User-Agent"))
-
- if accepts == "" || !checkAccepts {
- accepts = "*/*"
- }
-
- // User agent has Mozilla and browser accepts */*
- return strings.Contains(userAgent, "mozilla") && strings.Contains(accepts, "*/*")
-}
diff --git a/pkg/schemaserver/parse/mux.go b/pkg/schemaserver/parse/mux.go
deleted file mode 100644
index 83dd2e2..0000000
--- a/pkg/schemaserver/parse/mux.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package parse
-
-import (
- "net/http"
-
- "github.com/gorilla/mux"
- "github.com/rancher/steve/pkg/schemaserver/types"
-)
-
-type Vars struct {
- Type string
- Name string
- Namespace string
- Link string
- Prefix string
- Action string
-}
-
-func Set(v Vars) mux.MatcherFunc {
- return func(request *http.Request, match *mux.RouteMatch) bool {
- if match.Vars == nil {
- match.Vars = map[string]string{}
- }
- if v.Type != "" {
- match.Vars["type"] = v.Type
- }
- if v.Name != "" {
- match.Vars["name"] = v.Name
- }
- if v.Link != "" {
- match.Vars["link"] = v.Link
- }
- if v.Prefix != "" {
- match.Vars["prefix"] = v.Prefix
- }
- if v.Action != "" {
- match.Vars["action"] = v.Action
- }
- if v.Namespace != "" {
- match.Vars["namespace"] = v.Namespace
- }
- return true
- }
-}
-
-func MuxURLParser(rw http.ResponseWriter, req *http.Request, schemas *types.APISchemas) (ParsedURL, error) {
- vars := mux.Vars(req)
- url := ParsedURL{
- Type: vars["type"],
- Name: vars["name"],
- Namespace: vars["namespace"],
- Link: vars["link"],
- Prefix: vars["prefix"],
- Method: req.Method,
- Action: vars["action"],
- Query: req.URL.Query(),
- }
-
- return url, nil
-}
diff --git a/pkg/schemaserver/parse/parse.go b/pkg/schemaserver/parse/parse.go
deleted file mode 100644
index e575e86..0000000
--- a/pkg/schemaserver/parse/parse.go
+++ /dev/null
@@ -1,172 +0,0 @@
-package parse
-
-import (
- "net/http"
- "net/url"
- "strings"
-
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/steve/pkg/schemaserver/urlbuilder"
-)
-
-const (
- maxFormSize = 2 * 1 << 20
-)
-
-var (
- allowedFormats = map[string]bool{
- "html": true,
- "json": true,
- "yaml": true,
- }
-)
-
-type ParsedURL struct {
- Type string
- Name string
- Namespace string
- Link string
- Method string
- Action string
- Prefix string
- SubContext map[string]string
- Query url.Values
-}
-
-type URLParser func(rw http.ResponseWriter, req *http.Request, schemas *types.APISchemas) (ParsedURL, error)
-
-type Parser func(apiOp *types.APIRequest, urlParser URLParser) error
-
-func Parse(apiOp *types.APIRequest, urlParser URLParser) error {
- var err error
-
- if apiOp.Request == nil {
- apiOp.Request, err = http.NewRequest("GET", "/", nil)
- if err != nil {
- return err
- }
- }
-
- apiOp = types.StoreAPIContext(apiOp)
-
- if apiOp.Method == "" {
- apiOp.Method = parseMethod(apiOp.Request)
- }
- if apiOp.ResponseFormat == "" {
- apiOp.ResponseFormat = parseResponseFormat(apiOp.Request)
- }
-
- // The response format is guaranteed to be set even in the event of an error
- parsedURL, err := urlParser(apiOp.Response, apiOp.Request, apiOp.Schemas)
- // wait to check error, want to set as much as possible
-
- if apiOp.Type == "" {
- apiOp.Type = parsedURL.Type
- }
- if apiOp.Name == "" {
- apiOp.Name = parsedURL.Name
- }
- if apiOp.Link == "" {
- apiOp.Link = parsedURL.Link
- }
- if apiOp.Action == "" {
- apiOp.Action = parsedURL.Action
- }
- if apiOp.Query == nil {
- apiOp.Query = parsedURL.Query
- }
- if apiOp.Method == "" && parsedURL.Method != "" {
- apiOp.Method = parsedURL.Method
- }
- if apiOp.URLPrefix == "" {
- apiOp.URLPrefix = parsedURL.Prefix
- }
- if apiOp.Namespace == "" {
- apiOp.Namespace = parsedURL.Namespace
- }
-
- if apiOp.URLBuilder == nil {
- // make error local to not override the outer error we have yet to check
- var err error
- apiOp.URLBuilder, err = urlbuilder.New(apiOp.Request, &urlbuilder.DefaultPathResolver{
- Prefix: apiOp.URLPrefix,
- }, apiOp.Schemas)
- if err != nil {
- return err
- }
- }
-
- if err != nil {
- return err
- }
-
- if apiOp.Schema == nil && apiOp.Schemas != nil {
- apiOp.Schema = apiOp.Schemas.LookupSchema(apiOp.Type)
- }
-
- if apiOp.Schema != nil && apiOp.Type == "" {
- apiOp.Type = apiOp.Schema.ID
- }
-
- if err := ValidateMethod(apiOp); err != nil {
- return err
- }
-
- return nil
-}
-
-func parseResponseFormat(req *http.Request) string {
- format := req.URL.Query().Get("_format")
-
- if format != "" {
- format = strings.TrimSpace(strings.ToLower(format))
- }
-
- /* Format specified */
- if allowedFormats[format] {
- return format
- }
-
- // User agent has Mozilla and browser accepts */*
- if IsBrowser(req, true) {
- return "html"
- }
-
- if isYaml(req) {
- return "yaml"
- }
- return "json"
-}
-
-func isYaml(req *http.Request) bool {
- return strings.Contains(req.Header.Get("Accept"), "application/yaml")
-}
-
-func parseMethod(req *http.Request) string {
- method := req.URL.Query().Get("_method")
- if method == "" {
- method = req.Method
- }
- return method
-}
-
-func Body(req *http.Request) (types.APIObject, error) {
- req.ParseMultipartForm(maxFormSize)
- if req.MultipartForm != nil {
- return valuesToBody(req.MultipartForm.Value), nil
- }
-
- if req.PostForm != nil && len(req.PostForm) > 0 {
- return valuesToBody(map[string][]string(req.Form)), nil
- }
-
- return ReadBody(req)
-}
-
-func valuesToBody(input map[string][]string) types.APIObject {
- result := map[string]interface{}{}
- for k, v := range input {
- result[k] = v
- }
- return toAPI(result)
-}
diff --git a/pkg/schemaserver/parse/read_input.go b/pkg/schemaserver/parse/read_input.go
deleted file mode 100644
index a3e0d45..0000000
--- a/pkg/schemaserver/parse/read_input.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package parse
-
-import (
- "encoding/json"
- "fmt"
- "io"
- "net/http"
-
- "github.com/rancher/steve/pkg/schemaserver/httperror"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/wrangler/pkg/data/convert"
- "github.com/rancher/wrangler/pkg/schemas/validation"
- "k8s.io/apimachinery/pkg/util/yaml"
-)
-
-const reqMaxSize = (2 * 1 << 20) + 1
-
-var bodyMethods = map[string]bool{
- http.MethodPut: true,
- http.MethodPost: true,
-}
-
-type Decode func(interface{}) error
-
-func ReadBody(req *http.Request) (types.APIObject, error) {
- if !bodyMethods[req.Method] {
- return types.APIObject{}, nil
- }
-
- decode := getDecoder(req, io.LimitReader(req.Body, maxFormSize))
-
- data := map[string]interface{}{}
- if err := decode(&data); err != nil {
- return types.APIObject{}, httperror.NewAPIError(validation.InvalidBodyContent,
- fmt.Sprintf("Failed to parse body: %v", err))
- }
-
- return toAPI(data), nil
-}
-
-func toAPI(data map[string]interface{}) types.APIObject {
- return types.APIObject{
- Type: convert.ToString(data["type"]),
- ID: convert.ToString(data["id"]),
- Object: data,
- }
-}
-
-func getDecoder(req *http.Request, reader io.Reader) Decode {
- if req.Header.Get("Content-type") == "application/yaml" {
- return yaml.NewYAMLToJSONDecoder(reader).Decode
- }
- decoder := json.NewDecoder(reader)
- decoder.UseNumber()
- return decoder.Decode
-}
diff --git a/pkg/schemaserver/parse/validate.go b/pkg/schemaserver/parse/validate.go
deleted file mode 100644
index 0de2fdb..0000000
--- a/pkg/schemaserver/parse/validate.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package parse
-
-import (
- "fmt"
- "net/http"
-
- "github.com/rancher/steve/pkg/schemaserver/httperror"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/wrangler/pkg/schemas/validation"
-)
-
-var (
- supportedMethods = map[string]bool{
- http.MethodPost: true,
- http.MethodGet: true,
- http.MethodPut: true,
- http.MethodPatch: true,
- http.MethodDelete: true,
- }
-)
-
-func ValidateMethod(request *types.APIRequest) error {
- if request.Action != "" && request.Method == http.MethodPost {
- return nil
- }
-
- if !supportedMethods[request.Method] {
- return httperror.NewAPIError(validation.MethodNotAllowed, fmt.Sprintf("Invalid method %s not supported", request.Method))
- }
-
- if request.Type == "" || request.Schema == nil || request.Link != "" {
- return nil
- }
-
- allowed := request.Schema.ResourceMethods
- if request.Name == "" {
- allowed = request.Schema.CollectionMethods
- }
-
- for _, method := range allowed {
- if method == request.Method {
- return nil
- }
- }
-
- return httperror.NewAPIError(validation.MethodNotAllowed, fmt.Sprintf("Method %s not supported", request.Method))
-}
diff --git a/pkg/schemaserver/server/access.go b/pkg/schemaserver/server/access.go
deleted file mode 100644
index 06de94d..0000000
--- a/pkg/schemaserver/server/access.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package server
-
-import (
- "net/http"
-
- "github.com/rancher/steve/pkg/schemaserver/httperror"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/wrangler/pkg/schemas/validation"
- "github.com/rancher/wrangler/pkg/slice"
-)
-
-type SchemaBasedAccess struct {
-}
-
-func (*SchemaBasedAccess) CanCreate(apiOp *types.APIRequest, schema *types.APISchema) error {
- if slice.ContainsString(schema.CollectionMethods, http.MethodPost) {
- return nil
- }
- return httperror.NewAPIError(validation.PermissionDenied, "can not create "+schema.ID)
-}
-
-func (*SchemaBasedAccess) CanGet(apiOp *types.APIRequest, schema *types.APISchema) error {
- if slice.ContainsString(schema.ResourceMethods, http.MethodGet) {
- return nil
- }
- return httperror.NewAPIError(validation.PermissionDenied, "can not get "+schema.ID)
-}
-
-func (*SchemaBasedAccess) CanList(apiOp *types.APIRequest, schema *types.APISchema) error {
- if slice.ContainsString(schema.CollectionMethods, http.MethodGet) {
- return nil
- }
- return httperror.NewAPIError(validation.PermissionDenied, "can not list "+schema.ID)
-}
-
-func (*SchemaBasedAccess) CanUpdate(apiOp *types.APIRequest, obj types.APIObject, schema *types.APISchema) error {
- if slice.ContainsString(schema.ResourceMethods, http.MethodPut) {
- return nil
- }
- return httperror.NewAPIError(validation.PermissionDenied, "can not update "+schema.ID)
-}
-
-func (*SchemaBasedAccess) CanDelete(apiOp *types.APIRequest, obj types.APIObject, schema *types.APISchema) error {
- if slice.ContainsString(schema.ResourceMethods, http.MethodDelete) {
- return nil
- }
- return httperror.NewAPIError(validation.PermissionDenied, "can not delete "+schema.ID)
-}
-
-func (a *SchemaBasedAccess) CanWatch(apiOp *types.APIRequest, schema *types.APISchema) error {
- return a.CanList(apiOp, schema)
-}
-
-func (*SchemaBasedAccess) CanAction(apiOp *types.APIRequest, schema *types.APISchema, name string) error {
- if _, ok := schema.ActionHandlers[name]; ok {
- return httperror.NewAPIError(validation.PermissionDenied, "no such action "+name)
- }
- return nil
-}
diff --git a/pkg/schemaserver/server/server.go b/pkg/schemaserver/server/server.go
deleted file mode 100644
index e742719..0000000
--- a/pkg/schemaserver/server/server.go
+++ /dev/null
@@ -1,220 +0,0 @@
-package server
-
-import (
- "net/http"
-
- "github.com/rancher/steve/pkg/schemaserver/builtin"
- "github.com/rancher/steve/pkg/schemaserver/handlers"
- "github.com/rancher/steve/pkg/schemaserver/parse"
- "github.com/rancher/steve/pkg/schemaserver/subscribe"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/steve/pkg/schemaserver/writer"
- "github.com/rancher/wrangler/pkg/schemas/validation"
-)
-
-type RequestHandler interface {
- http.Handler
-
- GetSchemas() *types.APISchemas
- Handle(apiOp *types.APIRequest)
-}
-
-type Server struct {
- ResponseWriters map[string]types.ResponseWriter
- Schemas *types.APISchemas
- Defaults Defaults
- AccessControl types.AccessControl
- Parser parse.Parser
- URLParser parse.URLParser
-}
-
-type Defaults struct {
- ByIDHandler types.RequestHandler
- ListHandler types.RequestListHandler
- CreateHandler types.RequestHandler
- DeleteHandler types.RequestHandler
- UpdateHandler types.RequestHandler
- ErrorHandler types.ErrorHandler
-}
-
-func DefaultAPIServer() *Server {
- s := &Server{
- Schemas: types.EmptyAPISchemas().MustAddSchemas(builtin.Schemas),
- ResponseWriters: map[string]types.ResponseWriter{
- "json": &writer.GzipWriter{
- ResponseWriter: &writer.EncodingResponseWriter{
- ContentType: "application/json",
- Encoder: types.JSONEncoder,
- },
- },
- "html": &writer.GzipWriter{
- ResponseWriter: &writer.HTMLResponseWriter{
- EncodingResponseWriter: writer.EncodingResponseWriter{
- Encoder: types.JSONEncoder,
- ContentType: "application/json",
- },
- },
- },
- "yaml": &writer.GzipWriter{
- ResponseWriter: &writer.EncodingResponseWriter{
- ContentType: "application/yaml",
- Encoder: types.YAMLEncoder,
- },
- },
- },
- AccessControl: &SchemaBasedAccess{},
- Defaults: Defaults{
- ByIDHandler: handlers.ByIDHandler,
- CreateHandler: handlers.CreateHandler,
- DeleteHandler: handlers.DeleteHandler,
- UpdateHandler: handlers.UpdateHandler,
- ListHandler: handlers.ListHandler,
- ErrorHandler: handlers.ErrorHandler,
- },
- Parser: parse.Parse,
- URLParser: parse.MuxURLParser,
- }
-
- subscribe.Register(s.Schemas)
- return s
-}
-
-func (s *Server) setDefaults(ctx *types.APIRequest) {
- if ctx.ResponseWriter == nil {
- ctx.ResponseWriter = s.ResponseWriters[ctx.ResponseFormat]
- if ctx.ResponseWriter == nil {
- ctx.ResponseWriter = s.ResponseWriters["json"]
- }
- }
-
- ctx.AccessControl = s.AccessControl
-
- if ctx.Schemas == nil {
- ctx.Schemas = s.Schemas
- }
-}
-
-func (s *Server) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
- s.Handle(&types.APIRequest{
- Request: req,
- Response: rw,
- })
-}
-
-func (s *Server) Handle(apiOp *types.APIRequest) {
- s.handle(apiOp, s.Parser)
-}
-
-func (s *Server) handle(apiOp *types.APIRequest, parser parse.Parser) {
- if apiOp.Schemas == nil {
- apiOp.Schemas = s.Schemas
- }
-
- if err := parser(apiOp, parse.MuxURLParser); err != nil {
- // ensure defaults set so writer is assigned
- s.setDefaults(apiOp)
- s.handleError(apiOp, err)
- return
- }
-
- s.setDefaults(apiOp)
-
- if code, data, err := s.handleOp(apiOp); err != nil {
- s.handleError(apiOp, err)
- } else if obj, ok := data.(types.APIObject); ok {
- apiOp.WriteResponse(code, obj)
- } else if list, ok := data.(types.APIObjectList); ok {
- apiOp.WriteResponseList(code, list)
- } else if code > http.StatusOK {
- apiOp.Response.WriteHeader(code)
- }
-}
-
-func (s *Server) handleOp(apiOp *types.APIRequest) (int, interface{}, error) {
- if err := CheckCSRF(apiOp); err != nil {
- return 0, nil, err
- }
-
- action, err := ValidateAction(apiOp)
- if err != nil {
- return 0, nil, err
- }
-
- if apiOp.Schema == nil {
- return http.StatusNotFound, nil, nil
- }
-
- if action != nil {
- return http.StatusOK, nil, handleAction(apiOp)
- }
-
- switch apiOp.Method {
- case http.MethodGet:
- if apiOp.Name == "" {
- data, err := handleList(apiOp, apiOp.Schema.ListHandler, s.Defaults.ListHandler)
- return http.StatusOK, data, err
- }
- data, err := handle(apiOp, apiOp.Schema.ByIDHandler, s.Defaults.ByIDHandler)
- return http.StatusOK, data, err
- case http.MethodPatch:
- fallthrough
- case http.MethodPut:
- data, err := handle(apiOp, apiOp.Schema.UpdateHandler, s.Defaults.UpdateHandler)
- return http.StatusOK, data, err
- case http.MethodPost:
- data, err := handle(apiOp, apiOp.Schema.CreateHandler, s.Defaults.CreateHandler)
- return http.StatusCreated, data, err
- case http.MethodDelete:
- data, err := handle(apiOp, apiOp.Schema.DeleteHandler, s.Defaults.DeleteHandler)
- return http.StatusOK, data, err
- }
-
- return http.StatusNotFound, nil, nil
-}
-
-func handleList(apiOp *types.APIRequest, custom types.RequestListHandler, handler types.RequestListHandler) (types.APIObjectList, error) {
- if custom != nil {
- return custom(apiOp)
- }
- return handler(apiOp)
-}
-
-func handle(apiOp *types.APIRequest, custom types.RequestHandler, handler types.RequestHandler) (types.APIObject, error) {
- if custom != nil {
- return custom(apiOp)
- }
- return handler(apiOp)
-}
-
-func handleAction(context *types.APIRequest) error {
- if err := context.AccessControl.CanAction(context, context.Schema, context.Action); err != nil {
- return err
- }
- if handler, ok := context.Schema.ActionHandlers[context.Action]; ok {
- handler.ServeHTTP(context.Response, context.Request)
- return validation.ErrComplete
- }
- return nil
-}
-
-func (s *Server) handleError(apiOp *types.APIRequest, err error) {
- if apiOp.Schema != nil && apiOp.Schema.ErrorHandler != nil {
- apiOp.Schema.ErrorHandler(apiOp, err)
- } else if s.Defaults.ErrorHandler != nil {
- s.Defaults.ErrorHandler(apiOp, err)
- }
-}
-
-func (s *Server) CustomAPIUIResponseWriter(cssURL, jsURL, version writer.StringGetter) {
- wi, ok := s.ResponseWriters["html"]
- if !ok {
- return
- }
- w, ok := wi.(*writer.HTMLResponseWriter)
- if !ok {
- return
- }
- w.CSSURL = cssURL
- w.JSURL = jsURL
- w.APIUIVersion = version
-}
diff --git a/pkg/schemaserver/server/validate.go b/pkg/schemaserver/server/validate.go
deleted file mode 100644
index 4242266..0000000
--- a/pkg/schemaserver/server/validate.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package server
-
-import (
- "crypto/rand"
- "encoding/hex"
- "fmt"
- "net/http"
-
- "github.com/rancher/steve/pkg/schemaserver/httperror"
- "github.com/rancher/steve/pkg/schemaserver/parse"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/wrangler/pkg/schemas"
- "github.com/rancher/wrangler/pkg/schemas/validation"
-)
-
-const (
- csrfCookie = "CSRF"
- csrfHeader = "X-API-CSRF"
-)
-
-func ValidateAction(request *types.APIRequest) (*schemas.Action, error) {
- if request.Action == "" || request.Link != "" || request.Method != http.MethodPost {
- return nil, nil
- }
-
- if err := request.AccessControl.CanAction(request, request.Schema, request.Action); err != nil {
- return nil, err
- }
-
- actions := request.Schema.CollectionActions
- if request.Name != "" {
- actions = request.Schema.ResourceActions
- }
-
- action, ok := actions[request.Action]
- if !ok {
- return nil, httperror.NewAPIError(validation.InvalidAction, fmt.Sprintf("Invalid action: %s", request.Action))
- }
-
- return &action, nil
-}
-
-func CheckCSRF(apiOp *types.APIRequest) error {
- if !parse.IsBrowser(apiOp.Request, false) {
- return nil
- }
-
- cookie, err := apiOp.Request.Cookie(csrfCookie)
- if err == http.ErrNoCookie {
- bytes := make([]byte, 5)
- _, err := rand.Read(bytes)
- if err != nil {
- return httperror.WrapAPIError(err, validation.ServerError, "Failed in CSRF processing")
- }
-
- cookie = &http.Cookie{
- Name: csrfCookie,
- Value: hex.EncodeToString(bytes),
- Path: "/",
- Secure: true,
- }
-
- http.SetCookie(apiOp.Response, cookie)
- } else if err != nil {
- return httperror.NewAPIError(validation.InvalidCSRFToken, "Failed to parse cookies")
- } else if apiOp.Method != http.MethodGet {
- /*
- * Very important to use apiOp.Method and not apiOp.Request.Method. The client can override the HTTP method with _method
- */
- if cookie.Value == apiOp.Request.Header.Get(csrfHeader) {
- // Good
- } else if cookie.Value == apiOp.Request.URL.Query().Get(csrfCookie) {
- // Good
- } else {
- return httperror.NewAPIError(validation.InvalidCSRFToken, "Invalid CSRF token")
- }
- }
-
- return nil
-}
diff --git a/pkg/schemaserver/store/apiroot/apiroot.go b/pkg/schemaserver/store/apiroot/apiroot.go
deleted file mode 100644
index 2bc8be7..0000000
--- a/pkg/schemaserver/store/apiroot/apiroot.go
+++ /dev/null
@@ -1,135 +0,0 @@
-package apiroot
-
-import (
- "net/http"
- "strings"
-
- "github.com/rancher/steve/pkg/schemaserver/store/empty"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/wrangler/pkg/schemas"
-)
-
-func Register(apiSchemas *types.APISchemas, versions, roots []string) {
- apiSchemas.MustAddSchema(types.APISchema{
- Schema: &schemas.Schema{
- ID: "apiRoot",
- CollectionMethods: []string{"GET"},
- ResourceMethods: []string{"GET"},
- ResourceFields: map[string]schemas.Field{
- "apiVersion": {Type: "map[json]"},
- "path": {Type: "string"},
- },
- },
- Formatter: Formatter,
- Store: NewAPIRootStore(versions, roots),
- })
-}
-
-func Formatter(apiOp *types.APIRequest, resource *types.RawResource) {
- data := resource.APIObject.Data()
- path, _ := data["path"].(string)
- if path == "" {
- return
- }
- delete(data, "path")
-
- resource.Links["root"] = apiOp.URLBuilder.RelativeToRoot(path)
-
- if data, isAPIRoot := data["apiVersion"].(map[string]interface{}); isAPIRoot {
- apiVersion := apiVersionFromMap(apiOp.Schemas, data)
- resource.Links["self"] = apiOp.URLBuilder.RelativeToRoot(apiVersion)
-
- resource.Links["schemas"] = apiOp.URLBuilder.RelativeToRoot(path)
- for _, schema := range apiOp.Schemas.Schemas {
- addCollectionLink(apiOp, schema, resource.Links)
- }
- }
-
- return
-}
-
-func addCollectionLink(apiOp *types.APIRequest, schema *types.APISchema, links map[string]string) {
- collectionLink := getSchemaCollectionLink(apiOp, schema)
- if collectionLink != "" {
- links[schema.PluralName] = collectionLink
- }
-}
-
-func getSchemaCollectionLink(apiOp *types.APIRequest, schema *types.APISchema) string {
- if schema != nil && contains(schema.CollectionMethods, http.MethodGet) {
- return apiOp.URLBuilder.Collection(schema)
- }
- return ""
-}
-
-type Store struct {
- empty.Store
- roots []string
- versions []string
-}
-
-func NewAPIRootStore(versions []string, roots []string) types.Store {
- return &Store{
- roots: roots,
- versions: versions,
- }
-}
-
-func (a *Store) ByID(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) {
- return types.DefaultByID(a, apiOp, schema, id)
-}
-
-func (a *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.APIObjectList, error) {
- var roots types.APIObjectList
-
- versions := a.versions
-
- for _, version := range versions {
- roots.Objects = append(roots.Objects, types.APIObject{
- Type: "apiRoot",
- ID: version,
- Object: apiVersionToAPIRootMap(version),
- })
- }
-
- for _, root := range a.roots {
- parts := strings.SplitN(root, ":", 2)
- if len(parts) == 2 {
- roots.Objects = append(roots.Objects, types.APIObject{
- Type: "apiRoot",
- ID: parts[0],
- Object: map[string]interface{}{
- "id": parts[0],
- "path": parts[1],
- },
- })
- }
- }
-
- return roots, nil
-}
-
-func apiVersionToAPIRootMap(version string) map[string]interface{} {
- return map[string]interface{}{
- "id": version,
- "type": "apiRoot",
- "apiVersion": map[string]interface{}{
- "version": version,
- },
- "path": "/" + version,
- }
-}
-
-func apiVersionFromMap(schemas *types.APISchemas, apiVersion map[string]interface{}) string {
- version, _ := apiVersion["version"].(string)
- return version
-}
-
-func contains(list []string, needle string) bool {
- for _, v := range list {
- if v == needle {
- return true
- }
- }
- return false
-}
diff --git a/pkg/schemaserver/store/empty/empty_store.go b/pkg/schemaserver/store/empty/empty_store.go
deleted file mode 100644
index 47d49a2..0000000
--- a/pkg/schemaserver/store/empty/empty_store.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package empty
-
-import (
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/wrangler/pkg/schemas/validation"
-)
-
-type Store struct {
-}
-
-func (e *Store) Delete(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) {
- return types.APIObject{}, validation.NotFound
-}
-
-func (e *Store) ByID(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) {
- return types.APIObject{}, validation.NotFound
-}
-
-func (e *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.APIObjectList, error) {
- return types.APIObjectList{}, validation.NotFound
-}
-
-func (e *Store) Create(apiOp *types.APIRequest, schema *types.APISchema, data types.APIObject) (types.APIObject, error) {
- return types.APIObject{}, validation.NotFound
-}
-
-func (e *Store) Update(apiOp *types.APIRequest, schema *types.APISchema, data types.APIObject, id string) (types.APIObject, error) {
- return types.APIObject{}, validation.NotFound
-}
-
-func (e *Store) Watch(apiOp *types.APIRequest, schema *types.APISchema, wr types.WatchRequest) (chan types.APIEvent, error) {
- return nil, nil
-}
diff --git a/pkg/schemaserver/store/schema/schema_store.go b/pkg/schemaserver/store/schema/schema_store.go
deleted file mode 100644
index ed643ad..0000000
--- a/pkg/schemaserver/store/schema/schema_store.go
+++ /dev/null
@@ -1,105 +0,0 @@
-package schema
-
-import (
- "github.com/rancher/wrangler/pkg/schemas/validation"
-
- "github.com/rancher/steve/pkg/schemaserver/httperror"
- "github.com/rancher/steve/pkg/schemaserver/store/empty"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/wrangler/pkg/schemas/definition"
-)
-
-type Store struct {
- empty.Store
-}
-
-func NewSchemaStore() types.Store {
- return &Store{}
-}
-
-func toAPIObject(schema *types.APISchema) types.APIObject {
- s := schema.DeepCopy()
- delete(s.Schema.Attributes, "access")
- return types.APIObject{
- Type: "schema",
- ID: schema.ID,
- Object: s,
- }
-}
-
-func (s *Store) ByID(apiOp *types.APIRequest, schema *types.APISchema, id string) (types.APIObject, error) {
- schema = apiOp.Schemas.LookupSchema(id)
- if schema == nil {
- return types.APIObject{}, httperror.NewAPIError(validation.NotFound, "no such schema")
- }
- return toAPIObject(schema), nil
-}
-
-func (s *Store) List(apiOp *types.APIRequest, schema *types.APISchema) (types.APIObjectList, error) {
- return FilterSchemas(apiOp, apiOp.Schemas.Schemas), nil
-}
-
-func FilterSchemas(apiOp *types.APIRequest, schemaMap map[string]*types.APISchema) types.APIObjectList {
- schemas := types.APIObjectList{}
-
- included := map[string]bool{}
- for _, schema := range schemaMap {
- if included[schema.ID] {
- continue
- }
-
- if apiOp.AccessControl.CanList(apiOp, schema) == nil || apiOp.AccessControl.CanGet(apiOp, schema) == nil {
- schemas = addSchema(apiOp, schema, schemaMap, schemas, included)
- }
- }
-
- return schemas
-}
-
-func addSchema(apiOp *types.APIRequest, schema *types.APISchema, schemaMap map[string]*types.APISchema, schemas types.APIObjectList, included map[string]bool) types.APIObjectList {
- included[schema.ID] = true
- schemas = traverseAndAdd(apiOp, schema, schemaMap, schemas, included)
- schemas.Objects = append(schemas.Objects, toAPIObject(schema))
- return schemas
-}
-
-func traverseAndAdd(apiOp *types.APIRequest, schema *types.APISchema, schemaMap map[string]*types.APISchema, schemas types.APIObjectList, included map[string]bool) types.APIObjectList {
- for _, field := range schema.ResourceFields {
- t := ""
- subType := field.Type
- for subType != t {
- t = subType
- subType = definition.SubType(t)
- }
-
- if refSchema, ok := schemaMap[t]; ok && !included[t] {
- schemas = addSchema(apiOp, refSchema, schemaMap, schemas, included)
- }
- }
-
- for _, action := range schema.ResourceActions {
- for _, t := range []string{action.Output, action.Input} {
- if t == "" {
- continue
- }
-
- if refSchema, ok := schemaMap[t]; ok && !included[t] {
- schemas = addSchema(apiOp, refSchema, schemaMap, schemas, included)
- }
- }
- }
-
- for _, action := range schema.CollectionActions {
- for _, t := range []string{action.Output, action.Input} {
- if t == "" {
- continue
- }
-
- if refSchema, ok := schemaMap[t]; ok && !included[t] {
- schemas = addSchema(apiOp, refSchema, schemaMap, schemas, included)
- }
- }
- }
-
- return schemas
-}
diff --git a/pkg/schemaserver/subscribe/convert.go b/pkg/schemaserver/subscribe/convert.go
deleted file mode 100644
index 06c3fd5..0000000
--- a/pkg/schemaserver/subscribe/convert.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package subscribe
-
-import (
- "io"
-
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/steve/pkg/schemaserver/writer"
-)
-
-type Converter struct {
- writer.EncodingResponseWriter
- apiOp *types.APIRequest
- obj interface{}
-}
-
-func MarshallObject(apiOp *types.APIRequest, event types.APIEvent) types.APIEvent {
- if event.Error != nil {
- return event
- }
-
- data, err := newConverter(apiOp).ToAPIObject(event.Object)
- if err != nil {
- event.Error = err
- return event
- }
-
- event.Data = data
- return event
-}
-
-func newConverter(apiOp *types.APIRequest) *Converter {
- c := &Converter{
- apiOp: apiOp,
- }
- c.EncodingResponseWriter = writer.EncodingResponseWriter{
- ContentType: "application/json",
- Encoder: c.Encoder,
- }
- return c
-}
-
-func (c *Converter) ToAPIObject(data types.APIObject) (interface{}, error) {
- c.obj = nil
- if err := c.Body(c.apiOp, nil, data); err != nil {
- return types.APIObject{}, err
- }
- return c.obj, nil
-}
-
-func (c *Converter) Encoder(_ io.Writer, obj interface{}) error {
- c.obj = obj
- return nil
-}
diff --git a/pkg/schemaserver/subscribe/handler.go b/pkg/schemaserver/subscribe/handler.go
deleted file mode 100644
index 29398a5..0000000
--- a/pkg/schemaserver/subscribe/handler.go
+++ /dev/null
@@ -1,79 +0,0 @@
-package subscribe
-
-import (
- "encoding/json"
- "time"
-
- "github.com/gorilla/websocket"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/wrangler/pkg/schemas/validation"
- "github.com/sirupsen/logrus"
-)
-
-var upgrader = websocket.Upgrader{
- HandshakeTimeout: 60 * time.Second,
- EnableCompression: true,
-}
-
-type Subscribe struct {
- Stop bool `json:"stop,omitempty"`
- ResourceType string `json:"resourceType,omitempty"`
- ResourceVersion string `json:"resourceVersion,omitempty"`
-}
-
-func Handler(apiOp *types.APIRequest) (types.APIObjectList, error) {
- err := handler(apiOp)
- if err != nil {
- logrus.Errorf("Error during subscribe %v", err)
- }
- return types.APIObjectList{}, validation.ErrComplete
-}
-
-func handler(apiOp *types.APIRequest) error {
- c, err := upgrader.Upgrade(apiOp.Response, apiOp.Request, nil)
- if err != nil {
- return err
- }
- defer c.Close()
-
- watches := NewWatchSession(apiOp)
- defer watches.Close()
-
- events := watches.Watch(c)
- t := time.NewTicker(30 * time.Second)
- defer t.Stop()
-
- for {
- select {
- case event, ok := <-events:
- if !ok {
- return nil
- }
- if err := writeData(apiOp, c, event); err != nil {
- return err
- }
- case <-t.C:
- if err := writeData(apiOp, c, types.APIEvent{Name: "ping"}); err != nil {
- return err
- }
- }
- }
-}
-
-func writeData(apiOp *types.APIRequest, c *websocket.Conn, event types.APIEvent) error {
- event = MarshallObject(apiOp, event)
- if event.Error != nil {
- event.Name = "resource.error"
- event.Data = map[string]interface{}{
- "error": event.Error.Error(),
- }
- }
-
- messageWriter, err := c.NextWriter(websocket.TextMessage)
- if err != nil {
- return err
- }
- defer messageWriter.Close()
-
- return json.NewEncoder(messageWriter).Encode(event)
-}
diff --git a/pkg/schemaserver/subscribe/register.go b/pkg/schemaserver/subscribe/register.go
deleted file mode 100644
index 458deb4..0000000
--- a/pkg/schemaserver/subscribe/register.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package subscribe
-
-import (
- "net/http"
-
- "github.com/rancher/steve/pkg/schemaserver/types"
-)
-
-func Register(schemas *types.APISchemas) {
- schemas.MustImportAndCustomize(Subscribe{}, func(schema *types.APISchema) {
- schema.CollectionMethods = []string{http.MethodGet}
- schema.ResourceMethods = []string{}
- schema.ListHandler = Handler
- schema.PluralName = "subscribe"
- })
-}
diff --git a/pkg/schemaserver/subscribe/watcher.go b/pkg/schemaserver/subscribe/watcher.go
deleted file mode 100644
index a08f46e..0000000
--- a/pkg/schemaserver/subscribe/watcher.go
+++ /dev/null
@@ -1,145 +0,0 @@
-package subscribe
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "sync"
-
- "github.com/gorilla/websocket"
- "github.com/rancher/steve/pkg/schemaserver/types"
-)
-
-type WatchSession struct {
- sync.Mutex
-
- apiOp *types.APIRequest
- watchers map[string]func()
- wg sync.WaitGroup
- ctx context.Context
- cancel func()
-}
-
-func (s *WatchSession) stop(id string, resp chan<- types.APIEvent) {
- s.Lock()
- defer s.Unlock()
- if cancel, ok := s.watchers[id]; ok {
- cancel()
- resp <- types.APIEvent{
- Name: "resource.stop",
- ResourceType: id,
- }
- }
- delete(s.watchers, id)
-}
-
-func (s *WatchSession) add(resourceType, revision string, resp chan<- types.APIEvent) {
- s.Lock()
- defer s.Unlock()
-
- ctx, cancel := context.WithCancel(s.ctx)
- s.watchers[resourceType] = cancel
-
- s.wg.Add(1)
- go func() {
- defer s.wg.Done()
- defer s.stop(resourceType, resp)
-
- if err := s.stream(ctx, resourceType, revision, resp); err != nil {
- sendErr(resp, err, resourceType)
- }
- }()
-}
-
-func (s *WatchSession) stream(ctx context.Context, resourceType, revision string, result chan<- types.APIEvent) error {
- schema := s.apiOp.Schemas.LookupSchema(resourceType)
- if schema == nil {
- return fmt.Errorf("failed to find schema %s", resourceType)
- } else if schema.Store == nil {
- return fmt.Errorf("schema %s does not support watching", resourceType)
- }
-
- if err := s.apiOp.AccessControl.CanWatch(s.apiOp, schema); err != nil {
- return err
- }
-
- c, err := schema.Store.Watch(s.apiOp.WithContext(ctx), schema, types.WatchRequest{Revision: revision})
- if err != nil {
- return err
- }
-
- result <- types.APIEvent{
- Name: "resource.start",
- ResourceType: resourceType,
- }
-
- for event := range c {
- result <- event
- }
-
- return nil
-}
-
-func NewWatchSession(apiOp *types.APIRequest) *WatchSession {
- ws := &WatchSession{
- apiOp: apiOp,
- watchers: map[string]func(){},
- }
-
- ws.ctx, ws.cancel = context.WithCancel(apiOp.Request.Context())
- return ws
-}
-
-func (s *WatchSession) Watch(conn *websocket.Conn) <-chan types.APIEvent {
- result := make(chan types.APIEvent, 100)
- go func() {
- defer close(result)
-
- if err := s.watch(conn, result); err != nil {
- sendErr(result, err, "")
- }
- }()
- return result
-}
-
-func (s *WatchSession) Close() {
- s.cancel()
- s.wg.Wait()
-}
-
-func (s *WatchSession) watch(conn *websocket.Conn, resp chan types.APIEvent) error {
- defer s.wg.Wait()
- defer s.cancel()
-
- for {
- _, r, err := conn.NextReader()
- if err != nil {
- return err
- }
-
- var sub Subscribe
-
- if err := json.NewDecoder(r).Decode(&sub); err != nil {
- sendErr(resp, err, "")
- continue
- }
-
- if sub.Stop {
- s.stop(sub.ResourceType, resp)
- } else {
- s.Lock()
- _, ok := s.watchers[sub.ResourceType]
- s.Unlock()
- if !ok {
- s.add(sub.ResourceType, sub.ResourceVersion, resp)
- }
- }
- }
-}
-
-func sendErr(resp chan<- types.APIEvent, err error, resourceType string) {
- resp <- types.APIEvent{
- ResourceType: resourceType,
- Error: err,
- }
-}
diff --git a/pkg/schemaserver/types/encoder.go b/pkg/schemaserver/types/encoder.go
deleted file mode 100644
index 0dcf562..0000000
--- a/pkg/schemaserver/types/encoder.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package types
-
-import (
- "encoding/json"
- "io"
-
- "github.com/ghodss/yaml"
-)
-
-func JSONEncoder(writer io.Writer, v interface{}) error {
- return json.NewEncoder(writer).Encode(v)
-}
-
-func YAMLEncoder(writer io.Writer, v interface{}) error {
- data, err := json.Marshal(v)
- if err != nil {
- return err
- }
- buf, err := yaml.JSONToYAML(data)
- if err != nil {
- return err
- }
- _, err = writer.Write(buf)
- return err
-}
diff --git a/pkg/schemaserver/types/schemas.go b/pkg/schemaserver/types/schemas.go
deleted file mode 100644
index a67a77e..0000000
--- a/pkg/schemaserver/types/schemas.go
+++ /dev/null
@@ -1,96 +0,0 @@
-package types
-
-import (
- "strings"
-
- "github.com/rancher/wrangler/pkg/schemas"
- "github.com/sirupsen/logrus"
-)
-
-type APISchemas struct {
- InternalSchemas *schemas.Schemas
- Schemas map[string]*APISchema
- index map[string]*APISchema
-}
-
-func EmptyAPISchemas() *APISchemas {
- return &APISchemas{
- InternalSchemas: schemas.EmptySchemas(),
- Schemas: map[string]*APISchema{},
- index: map[string]*APISchema{},
- }
-}
-
-func (a *APISchemas) MustAddSchema(obj APISchema) *APISchemas {
- err := a.AddSchema(obj)
- if err != nil {
- logrus.Fatalf("failed to add schema: %v", err)
- }
- return a
-}
-
-func (a *APISchemas) addInternalSchema(schema *schemas.Schema) *APISchema {
- apiSchema := &APISchema{
- Schema: schema,
- }
- a.Schemas[schema.ID] = apiSchema
- a.addToIndex(apiSchema)
-
- for _, f := range schema.ResourceFields {
- if subType := a.InternalSchemas.Schema(f.Type); subType == nil {
- continue
- } else if _, ok := a.Schemas[subType.ID]; !ok {
- a.addInternalSchema(subType)
- }
- }
-
- return apiSchema
-}
-
-func (a *APISchemas) MustImportAndCustomize(obj interface{}, f func(*APISchema)) {
- schema, err := a.InternalSchemas.Import(obj)
- if err != nil {
- panic(err)
- }
- apiSchema := a.addInternalSchema(schema)
- f(apiSchema)
-}
-
-func (a *APISchemas) MustAddSchemas(schemas *APISchemas) *APISchemas {
- if err := a.AddSchemas(schemas); err != nil {
- logrus.Fatalf("failed to add schemas: %v", err)
- }
- return a
-}
-
-func (a *APISchemas) AddSchemas(schema *APISchemas) error {
- for _, schema := range schema.Schemas {
- if err := a.AddSchema(*schema); err != nil {
- return err
- }
- }
- return nil
-}
-
-func (a *APISchemas) addToIndex(schema *APISchema) {
- a.index[strings.ToLower(schema.ID)] = schema
- a.index[strings.ToLower(schema.PluralName)] = schema
-}
-
-func (a *APISchemas) AddSchema(schema APISchema) error {
- if err := a.InternalSchemas.AddSchema(*schema.Schema); err != nil {
- return err
- }
- schema.Schema = a.InternalSchemas.Schema(schema.ID)
- a.Schemas[schema.ID] = &schema
- a.addToIndex(&schema)
- return nil
-}
-
-func (a *APISchemas) LookupSchema(name string) *APISchema {
- s, ok := a.Schemas[name]
- if ok {
- return s
- }
- return a.index[strings.ToLower(name)]
-}
diff --git a/pkg/schemaserver/types/server_types.go b/pkg/schemaserver/types/server_types.go
deleted file mode 100644
index a985e7f..0000000
--- a/pkg/schemaserver/types/server_types.go
+++ /dev/null
@@ -1,295 +0,0 @@
-package types
-
-import (
- "context"
- "encoding/json"
- "net/http"
- "net/url"
-
- "github.com/rancher/wrangler/pkg/data"
- "github.com/rancher/wrangler/pkg/data/convert"
- "github.com/rancher/wrangler/pkg/schemas/validation"
- meta2 "k8s.io/apimachinery/pkg/api/meta"
- "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apiserver/pkg/authentication/user"
- "k8s.io/apiserver/pkg/endpoints/request"
-)
-
-type RawResource struct {
- ID string `json:"id,omitempty" yaml:"id,omitempty"`
- Type string `json:"type,omitempty" yaml:"type,omitempty"`
- Schema *APISchema `json:"-" yaml:"-"`
- Links map[string]string `json:"links" yaml:"links,omitempty"`
- Actions map[string]string `json:"actions,omitempty" yaml:"actions,omitempty"`
- ActionLinks bool `json:"-" yaml:"-"`
- APIObject APIObject `json:"-" yaml:"-"`
-}
-
-type Pagination struct {
- Limit int `json:"limit,omitempty"`
- First string `json:"first,omitempty"`
- Next string `json:"next,omitempty"`
- Partial bool `json:"partial,omitempty"`
-}
-
-func (r *RawResource) MarshalJSON() ([]byte, error) {
- type r_ RawResource
- outer, err := json.Marshal((*r_)(r))
- if err != nil {
- return nil, err
- }
-
- last := len(outer) - 1
- if len(outer) < 2 || outer[last] != '}' {
- return outer, nil
- }
-
- data, err := json.Marshal(r.APIObject.Object)
- if err != nil {
- return nil, err
- }
-
- if len(data) < 3 || data[0] != '{' || data[len(data)-1] != '}' {
- return outer, nil
- }
-
- if outer[last-1] == '{' {
- outer[last] = ' '
- } else {
- outer[last] = ','
- }
-
- return append(outer, data[1:]...), nil
-}
-
-func (r *RawResource) AddAction(apiOp *APIRequest, name string) {
- r.Actions[name] = apiOp.URLBuilder.Action(r.Schema, r.ID, name)
-}
-
-type RequestHandler func(request *APIRequest) (APIObject, error)
-
-type RequestListHandler func(request *APIRequest) (APIObjectList, error)
-
-type Formatter func(request *APIRequest, resource *RawResource)
-
-type CollectionFormatter func(request *APIRequest, collection *GenericCollection)
-
-type ErrorHandler func(request *APIRequest, err error)
-
-type ResponseWriter interface {
- Write(apiOp *APIRequest, code int, obj APIObject)
- WriteList(apiOp *APIRequest, code int, obj APIObjectList)
-}
-
-type AccessControl interface {
- CanAction(apiOp *APIRequest, schema *APISchema, name string) error
- CanCreate(apiOp *APIRequest, schema *APISchema) error
- CanList(apiOp *APIRequest, schema *APISchema) error
- CanGet(apiOp *APIRequest, schema *APISchema) error
- CanUpdate(apiOp *APIRequest, obj APIObject, schema *APISchema) error
- CanDelete(apiOp *APIRequest, obj APIObject, schema *APISchema) error
- CanWatch(apiOp *APIRequest, schema *APISchema) error
-}
-
-type APIRequest struct {
- Action string
- Name string
- Type string
- Link string
- Method string
- Namespace string
- Schema *APISchema
- Schemas *APISchemas
- Query url.Values
- ResponseFormat string
- ResponseWriter ResponseWriter
- URLPrefix string
- URLBuilder URLBuilder
- AccessControl AccessControl
-
- Request *http.Request
- Response http.ResponseWriter
-}
-
-type apiOpKey struct{}
-
-func GetAPIContext(ctx context.Context) *APIRequest {
- apiOp, _ := ctx.Value(apiOpKey{}).(*APIRequest)
- return apiOp
-}
-
-func StoreAPIContext(apiOp *APIRequest) *APIRequest {
- ctx := context.WithValue(apiOp.Request.Context(), apiOpKey{}, apiOp)
- apiOp.Request = apiOp.Request.WithContext(ctx)
- return apiOp
-}
-
-func (r *APIRequest) WithContext(ctx context.Context) *APIRequest {
- result := *r
- result.Request = result.Request.WithContext(ctx)
- return &result
-}
-
-func (r *APIRequest) Context() context.Context {
- return r.Request.Context()
-}
-
-func (r *APIRequest) GetUser() string {
- user, ok := request.UserFrom(r.Request.Context())
- if ok {
- return user.GetName()
- }
- return ""
-}
-
-func (r *APIRequest) GetUserInfo() (user.Info, bool) {
- return request.UserFrom(r.Request.Context())
-}
-
-func (r *APIRequest) Option(key string) string {
- return r.Query.Get("_" + key)
-}
-
-func (r *APIRequest) WriteResponse(code int, obj APIObject) {
- r.ResponseWriter.Write(r, code, obj)
-}
-
-func (r *APIRequest) WriteResponseList(code int, list APIObjectList) {
- r.ResponseWriter.WriteList(r, code, list)
-}
-
-type URLBuilder interface {
- Current() string
-
- Collection(schema *APISchema) string
- CollectionAction(schema *APISchema, action string) string
- ResourceLink(schema *APISchema, id string) string
- Link(schema *APISchema, id string, linkName string) string
- Action(schema *APISchema, id string, action string) string
- Marker(marker string) string
-
- RelativeToRoot(path string) string
-}
-
-type Store interface {
- ByID(apiOp *APIRequest, schema *APISchema, id string) (APIObject, error)
- List(apiOp *APIRequest, schema *APISchema) (APIObjectList, error)
- Create(apiOp *APIRequest, schema *APISchema, data APIObject) (APIObject, error)
- Update(apiOp *APIRequest, schema *APISchema, data APIObject, id string) (APIObject, error)
- Delete(apiOp *APIRequest, schema *APISchema, id string) (APIObject, error)
- Watch(apiOp *APIRequest, schema *APISchema, w WatchRequest) (chan APIEvent, error)
-}
-
-func DefaultByID(store Store, apiOp *APIRequest, schema *APISchema, id string) (APIObject, error) {
- list, err := store.List(apiOp, schema)
- if err != nil {
- return APIObject{}, err
- }
-
- for _, item := range list.Objects {
- if item.ID == id {
- return item, nil
- }
- }
-
- return APIObject{}, validation.NotFound
-}
-
-type WatchRequest struct {
- Revision string
-}
-
-var (
- ChangeAPIEvent = "resource.change"
- RemoveAPIEvent = "resource.remove"
- CreateAPIEvent = "resource.create"
-)
-
-type APIEvent struct {
- Name string `json:"name,omitempty"`
- ResourceType string `json:"resourceType,omitempty"`
- Revision string `json:"revision,omitempty"`
- Object APIObject `json:"-"`
- Error error `json:"-"`
- // Data is the output format of the object
- Data interface{} `json:"data,omitempty"`
-}
-
-type APIObject struct {
- Type string
- ID string
- Object interface{}
-}
-
-type APIObjectList struct {
- Revision string
- Continue string
- Objects []APIObject
-}
-
-func (a *APIObject) Data() data.Object {
- if unstr, ok := a.Object.(*unstructured.Unstructured); ok {
- return unstr.Object
- }
- data, err := convert.EncodeToMap(a.Object)
- if err != nil {
- return convert.ToMapInterface(a.Object)
- }
- return data
-}
-
-func (a *APIObject) Name() string {
- if ro, ok := a.Object.(runtime.Object); ok {
- meta, err := meta2.Accessor(ro)
- if err == nil {
- return meta.GetName()
- }
- }
- return Name(a.Data())
-}
-
-func (a *APIObject) Namespace() string {
- if ro, ok := a.Object.(runtime.Object); ok {
- meta, err := meta2.Accessor(ro)
- if err == nil {
- return meta.GetNamespace()
- }
- }
- return Namespace(a.Data())
-}
-
-func Name(d map[string]interface{}) string {
- return convert.ToString(data.GetValueN(d, "metadata", "name"))
-}
-
-func Namespace(d map[string]interface{}) string {
- return convert.ToString(data.GetValueN(d, "metadata", "namespace"))
-}
-
-func APIChan(c <-chan APIEvent, f func(APIObject) APIObject) chan APIEvent {
- if c == nil {
- return nil
- }
- result := make(chan APIEvent)
- go func() {
- for data := range c {
- data.Object = f(data.Object)
- result <- data
- }
- close(result)
- }()
- return result
-}
-
-func FormatterChain(formatter Formatter, next Formatter) Formatter {
- return func(request *APIRequest, resource *RawResource) {
- formatter(request, resource)
- next(request, resource)
- }
-}
-
-func (r *APIRequest) Clone() *APIRequest {
- clone := *r
- return &clone
-}
diff --git a/pkg/schemaserver/types/types.go b/pkg/schemaserver/types/types.go
deleted file mode 100644
index 3549268..0000000
--- a/pkg/schemaserver/types/types.go
+++ /dev/null
@@ -1,103 +0,0 @@
-package types
-
-import (
- "net/http"
-
- "github.com/rancher/wrangler/pkg/schemas"
-)
-
-type Collection struct {
- Type string `json:"type,omitempty"`
- Links map[string]string `json:"links"`
- CreateTypes map[string]string `json:"createTypes,omitempty"`
- Actions map[string]string `json:"actions"`
- ResourceType string `json:"resourceType"`
- Pagination *Pagination `json:"pagination,omitempty"`
- Revision string `json:"revision,omitempty"`
- Continue string `json:"continue,omitempty"`
-}
-
-type GenericCollection struct {
- Collection
- Data []*RawResource `json:"data"`
-}
-
-var (
- ModifierEQ ModifierType = "eq"
- ModifierNE ModifierType = "ne"
- ModifierNull ModifierType = "null"
- ModifierNotNull ModifierType = "notnull"
- ModifierIn ModifierType = "in"
- ModifierNotIn ModifierType = "notin"
-)
-
-type ModifierType string
-
-type Condition struct {
- Modifier ModifierType `json:"modifier,omitempty"`
- Value interface{} `json:"value,omitempty"`
-}
-
-type Resource struct {
- ID string `json:"id,omitempty"`
- Type string `json:"type,omitempty"`
- Links map[string]string `json:"links"`
- Actions map[string]string `json:"actions"`
-}
-
-type NamedResource struct {
- Resource
- Name string `json:"name"`
- Description string `json:"description"`
-}
-
-type NamedResourceCollection struct {
- Collection
- Data []NamedResource `json:"data,omitempty"`
-}
-
-var ReservedFields = map[string]bool{
- "id": true,
- "type": true,
- "links": true,
- "actions": true,
-}
-
-type APISchema struct {
- *schemas.Schema
-
- ActionHandlers map[string]http.Handler `json:"-"`
- LinkHandlers map[string]http.Handler `json:"-"`
- ListHandler RequestListHandler `json:"-"`
- ByIDHandler RequestHandler `json:"-"`
- CreateHandler RequestHandler `json:"-"`
- DeleteHandler RequestHandler `json:"-"`
- UpdateHandler RequestHandler `json:"-"`
- Formatter Formatter `json:"-"`
- CollectionFormatter CollectionFormatter `json:"-"`
- ErrorHandler ErrorHandler `json:"-"`
- Store Store `json:"-"`
-}
-
-func copyHandlers(m map[string]http.Handler) map[string]http.Handler {
- if m == nil {
- return nil
- }
- result := make(map[string]http.Handler, len(m))
- for k, v := range m {
- result[k] = v
- }
-
- return result
-}
-func (a *APISchema) DeepCopy() *APISchema {
- r := *a
- r.ActionHandlers = copyHandlers(a.ActionHandlers)
- r.LinkHandlers = copyHandlers(a.ActionHandlers)
- r.Schema = r.Schema.DeepCopy()
- return &r
-}
-
-func (c *Collection) AddAction(apiOp *APIRequest, name string) {
- c.Actions[name] = apiOp.URLBuilder.CollectionAction(apiOp.Schema, name)
-}
diff --git a/pkg/schemaserver/urlbuilder/base.go b/pkg/schemaserver/urlbuilder/base.go
deleted file mode 100644
index bffcefe..0000000
--- a/pkg/schemaserver/urlbuilder/base.go
+++ /dev/null
@@ -1,67 +0,0 @@
-package urlbuilder
-
-import (
- "bytes"
- "fmt"
- "net/http"
- "net/url"
- "strings"
-)
-
-func ParseRequestURL(r *http.Request) string {
- scheme := GetScheme(r)
- host := GetHost(r, scheme)
- return fmt.Sprintf("%s://%s%s%s", scheme, host, r.Header.Get(PrefixHeader), r.URL.Path)
-}
-
-func GetHost(r *http.Request, scheme string) string {
- host := r.Header.Get(ForwardedAPIHostHeader)
- if host != "" {
- return host
- }
-
- host = strings.Split(r.Header.Get(ForwardedHostHeader), ",")[0]
- if host != "" {
- return host
- }
-
- return r.Host
-}
-
-func GetScheme(r *http.Request) string {
- scheme := r.Header.Get(ForwardedProtoHeader)
- if scheme != "" {
- switch scheme {
- case "ws":
- return "http"
- case "wss":
- return "https"
- default:
- return scheme
- }
- } else if r.TLS != nil {
- return "https"
- }
- return "http"
-}
-
-func ParseResponseURLBase(currentURL string, r *http.Request) (string, error) {
- path := r.URL.Path
-
- index := strings.LastIndex(currentURL, path)
- if index == -1 {
- // Fallback, if we can't find path in currentURL, then we just assume the base is the root of the web request
- u, err := url.Parse(currentURL)
- if err != nil {
- return "", err
- }
-
- buffer := bytes.Buffer{}
- buffer.WriteString(u.Scheme)
- buffer.WriteString("://")
- buffer.WriteString(u.Host)
- return buffer.String(), nil
- }
-
- return currentURL[0:index], nil
-}
diff --git a/pkg/schemaserver/urlbuilder/redirect.go b/pkg/schemaserver/urlbuilder/redirect.go
deleted file mode 100644
index d4a765c..0000000
--- a/pkg/schemaserver/urlbuilder/redirect.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package urlbuilder
-
-import (
- "bytes"
- "net/http"
- "net/url"
- "strings"
-)
-
-func RedirectRewrite(next http.Handler) http.Handler {
- return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
- prefix := req.Header.Get(PrefixHeader)
- if prefix == "" {
- next.ServeHTTP(rw, req)
- return
- }
- r := &redirector{
- ResponseWriter: rw,
- prefix: prefix,
- }
- if h, ok := rw.(http.Hijacker); ok {
- r.Hijacker = h
- }
- next.ServeHTTP(r, req)
- r.Close()
- })
-}
-
-type redirector struct {
- http.ResponseWriter
- http.Hijacker
- prefix string
- from, to string
- tempBuffer *bytes.Buffer
-}
-
-func (r *redirector) Write(content []byte) (int, error) {
- if r.tempBuffer == nil {
- return r.ResponseWriter.Write(content)
- }
- return r.tempBuffer.Write(content)
-}
-
-func (r *redirector) Close() error {
- if r.tempBuffer == nil || r.from == "" || r.to == "" {
- return nil
- }
-
- content := bytes.Replace(r.tempBuffer.Bytes(), []byte(r.from), []byte(r.to), -1)
- _, err := r.ResponseWriter.Write(content)
- r.tempBuffer = nil
- return err
-}
-
-func (r *redirector) WriteHeader(statusCode int) {
- defer func() {
- // the anonymous func is so that we take the new value of statusCode,
- // not copy it at invocation
- r.ResponseWriter.WriteHeader(statusCode)
- }()
-
- if statusCode != http.StatusMovedPermanently && statusCode != http.StatusFound {
- return
- }
-
- l := r.Header().Get("Location")
- if l == "" {
- return
- }
-
- u, _ := url.Parse(l)
- if !strings.HasPrefix(u.Path, r.prefix) {
- r.from = u.Path
- u.Path = r.prefix + u.Path
- r.Header().Set("Location", u.String())
- r.to = u.Path
- r.tempBuffer = &bytes.Buffer{}
- }
-
- statusCode = http.StatusFound
-}
diff --git a/pkg/schemaserver/urlbuilder/url.go b/pkg/schemaserver/urlbuilder/url.go
deleted file mode 100644
index d552f9a..0000000
--- a/pkg/schemaserver/urlbuilder/url.go
+++ /dev/null
@@ -1,136 +0,0 @@
-package urlbuilder
-
-import (
- "net/http"
- "net/url"
- "path"
- "strings"
-
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/wrangler/pkg/name"
-)
-
-const (
- PrefixHeader = "X-API-URL-Prefix"
- ForwardedAPIHostHeader = "X-API-Host"
- ForwardedHostHeader = "X-Forwarded-Host"
- ForwardedProtoHeader = "X-Forwarded-Proto"
- ForwardedPortHeader = "X-Forwarded-Port"
-)
-
-func NewPrefixed(r *http.Request, schemas *types.APISchemas, prefix string) (types.URLBuilder, error) {
- return New(r, &DefaultPathResolver{
- Prefix: prefix,
- }, schemas)
-}
-
-func New(r *http.Request, resolver PathResolver, schemas *types.APISchemas) (types.URLBuilder, error) {
- requestURL := ParseRequestURL(r)
- responseURLBase, err := ParseResponseURLBase(requestURL, r)
- if err != nil {
- return nil, err
- }
-
- builder := &DefaultURLBuilder{
- schemas: schemas,
- currentURL: requestURL,
- responseURLBase: responseURLBase,
- pathResolver: resolver,
- query: r.URL.Query(),
- }
-
- return builder, nil
-}
-
-type PathResolver interface {
- Schema(base string, schema *types.APISchema) string
-}
-
-type DefaultPathResolver struct {
- Prefix string
-}
-
-func (d *DefaultPathResolver) Schema(base string, schema *types.APISchema) string {
- return ConstructBasicURL(base, d.Prefix, schema.PluralName)
-}
-
-type DefaultURLBuilder struct {
- pathResolver PathResolver
- schemas *types.APISchemas
- currentURL string
- responseURLBase string
- query url.Values
-}
-
-func (u *DefaultURLBuilder) Marker(marker string) string {
- newValues := url.Values{}
- for k, v := range u.query {
- newValues[k] = v
- }
- newValues.Set("continue", marker)
- return u.Current() + "?" + newValues.Encode()
-}
-
-func (u *DefaultURLBuilder) Link(schema *types.APISchema, id string, linkName string) string {
- if strings.Contains(id, "/") {
- return u.schemaURL(schema, id, linkName)
- }
- return u.schemaURL(schema, id) + "?link=" + url.QueryEscape(linkName)
-}
-
-func (u *DefaultURLBuilder) ResourceLink(schema *types.APISchema, id string) string {
- return u.schemaURL(schema, id)
-}
-
-func (u *DefaultURLBuilder) Current() string {
- return u.currentURL
-}
-
-func (u *DefaultURLBuilder) RelativeToRoot(path string) string {
- if len(path) > 0 && path[0] != '/' {
- return u.responseURLBase + "/" + path
- }
- return u.responseURLBase + path
-}
-
-func (u *DefaultURLBuilder) Collection(schema *types.APISchema) string {
- return u.schemaURL(schema)
-}
-
-func (u *DefaultURLBuilder) schemaURL(schema *types.APISchema, parts ...string) string {
- base := []string{
- u.pathResolver.Schema(u.responseURLBase, schema),
- }
- return ConstructBasicURL(append(base, parts...)...)
-}
-
-func ConstructBasicURL(parts ...string) string {
- switch len(parts) {
- case 0:
- return ""
- case 1:
- return parts[0]
- default:
- base := parts[0]
- rest := path.Join(parts[1:]...)
- if !strings.HasSuffix(base, "/") && !strings.HasPrefix(rest, "/") {
- return base + "/" + rest
- }
- return base + rest
- }
-}
-
-func (u *DefaultURLBuilder) getPluralName(schema *types.APISchema) string {
- if schema.PluralName == "" {
- return strings.ToLower(name.GuessPluralName(schema.ID))
- }
- return strings.ToLower(schema.PluralName)
-}
-
-func (u *DefaultURLBuilder) Action(schema *types.APISchema, id, action string) string {
- return u.schemaURL(schema, id) + "?action=" + url.QueryEscape(action)
-}
-
-func (u *DefaultURLBuilder) CollectionAction(schema *types.APISchema, action string) string {
- return u.schemaURL(schema) + "?action=" + url.QueryEscape(action)
-}
diff --git a/pkg/schemaserver/writer/encoding.go b/pkg/schemaserver/writer/encoding.go
deleted file mode 100644
index 8115f2e..0000000
--- a/pkg/schemaserver/writer/encoding.go
+++ /dev/null
@@ -1,158 +0,0 @@
-package writer
-
-import (
- "io"
- "net/http"
- "strconv"
-
- "github.com/rancher/steve/pkg/schemaserver/types"
-)
-
-type EncodingResponseWriter struct {
- ContentType string
- Encoder func(io.Writer, interface{}) error
-}
-
-func (j *EncodingResponseWriter) start(apiOp *types.APIRequest, code int) {
- AddCommonResponseHeader(apiOp)
- apiOp.Response.Header().Set("content-type", j.ContentType)
- apiOp.Response.WriteHeader(code)
-}
-
-func (j *EncodingResponseWriter) Write(apiOp *types.APIRequest, code int, obj types.APIObject) {
- j.start(apiOp, code)
- j.Body(apiOp, apiOp.Response, obj)
-}
-
-func (j *EncodingResponseWriter) WriteList(apiOp *types.APIRequest, code int, list types.APIObjectList) {
- j.start(apiOp, code)
- j.BodyList(apiOp, apiOp.Response, list)
-}
-
-func (j *EncodingResponseWriter) Body(apiOp *types.APIRequest, writer io.Writer, obj types.APIObject) error {
- return j.Encoder(writer, j.convert(apiOp, obj))
-}
-
-func (j *EncodingResponseWriter) BodyList(apiOp *types.APIRequest, writer io.Writer, list types.APIObjectList) error {
- return j.Encoder(writer, j.convertList(apiOp, list))
-}
-
-func (j *EncodingResponseWriter) convertList(apiOp *types.APIRequest, input types.APIObjectList) *types.GenericCollection {
- collection := newCollection(apiOp, input)
- for _, value := range input.Objects {
- converted := j.convert(apiOp, value)
- collection.Data = append(collection.Data, converted)
- }
-
- if apiOp.Schema.CollectionFormatter != nil {
- apiOp.Schema.CollectionFormatter(apiOp, collection)
- }
-
- if collection.Data == nil {
- collection.Data = []*types.RawResource{}
- }
-
- return collection
-}
-
-func (j *EncodingResponseWriter) convert(context *types.APIRequest, input types.APIObject) *types.RawResource {
- schema := context.Schemas.LookupSchema(input.Type)
- if schema == nil {
- schema = context.Schema
- }
- if schema == nil {
- return nil
- }
-
- rawResource := &types.RawResource{
- ID: input.ID,
- Type: schema.ID,
- Schema: schema,
- Links: map[string]string{},
- Actions: map[string]string{},
- ActionLinks: context.Request.Header.Get("X-API-Action-Links") != "",
- APIObject: input,
- }
-
- j.addLinks(schema, context, input, rawResource)
-
- if schema.Formatter != nil {
- schema.Formatter(context, rawResource)
- }
-
- return rawResource
-}
-
-func (j *EncodingResponseWriter) addLinks(schema *types.APISchema, context *types.APIRequest, input types.APIObject, rawResource *types.RawResource) {
- if rawResource.ID == "" {
- return
- }
-
- self := context.URLBuilder.ResourceLink(rawResource.Schema, rawResource.ID)
- if _, ok := rawResource.Links["self"]; !ok {
- rawResource.Links["self"] = self
- }
- if _, ok := rawResource.Links["update"]; !ok {
- if context.AccessControl.CanUpdate(context, input, schema) == nil {
- rawResource.Links["update"] = self
- }
- }
- if _, ok := rawResource.Links["remove"]; !ok {
- if context.AccessControl.CanDelete(context, input, schema) == nil {
- rawResource.Links["remove"] = self
- }
- }
- for link := range schema.LinkHandlers {
- rawResource.Links[link] = context.URLBuilder.Link(schema, rawResource.ID, link)
- }
- for action := range schema.ActionHandlers {
- if rawResource.Actions == nil {
- rawResource.Actions = map[string]string{}
- }
- rawResource.Actions[action] = context.URLBuilder.Action(schema, rawResource.ID, action)
- }
-}
-
-func getLimit(req *http.Request) int {
- limit, err := strconv.Atoi(req.Header.Get("limit"))
- if err == nil && limit > 0 {
- return limit
- }
- return 0
-}
-
-func newCollection(apiOp *types.APIRequest, list types.APIObjectList) *types.GenericCollection {
- result := &types.GenericCollection{
- Collection: types.Collection{
- Type: "collection",
- ResourceType: apiOp.Type,
- CreateTypes: map[string]string{},
- Links: map[string]string{
- "self": apiOp.URLBuilder.Current(),
- },
- Actions: map[string]string{},
- Continue: list.Continue,
- Revision: list.Revision,
- },
- }
-
- partial := list.Continue != "" || apiOp.Query.Get("continue") != ""
- if partial {
- result.Pagination = &types.Pagination{
- Limit: getLimit(apiOp.Request),
- First: apiOp.URLBuilder.Current(),
- Partial: true,
- }
- if list.Continue != "" {
- result.Pagination.Next = apiOp.URLBuilder.Marker(list.Continue)
- }
- }
-
- if apiOp.Method == http.MethodGet {
- if apiOp.AccessControl.CanCreate(apiOp, apiOp.Schema) == nil {
- result.CreateTypes[apiOp.Schema.ID] = apiOp.URLBuilder.Collection(apiOp.Schema)
- }
- }
-
- return result
-}
diff --git a/pkg/schemaserver/writer/gzip.go b/pkg/schemaserver/writer/gzip.go
deleted file mode 100644
index c028fae..0000000
--- a/pkg/schemaserver/writer/gzip.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package writer
-
-import (
- "compress/gzip"
- "io"
- "io/ioutil"
- "net/http"
- "strings"
-
- "github.com/rancher/steve/pkg/schemaserver/types"
-)
-
-type GzipWriter struct {
- types.ResponseWriter
-}
-
-func setup(apiOp *types.APIRequest) (*types.APIRequest, io.Closer) {
- if !strings.Contains(apiOp.Request.Header.Get("Accept-Encoding"), "gzip") {
- return apiOp, ioutil.NopCloser(nil)
- }
-
- apiOp.Response.Header().Set("Content-Encoding", "gzip")
- apiOp.Response.Header().Del("Content-Length")
-
- gz := gzip.NewWriter(apiOp.Response)
- gzw := &gzipResponseWriter{Writer: gz, ResponseWriter: apiOp.Response}
-
- newOp := *apiOp
- newOp.Response = gzw
- return &newOp, gz
-}
-
-func (g *GzipWriter) Write(apiOp *types.APIRequest, code int, obj types.APIObject) {
- apiOp, closer := setup(apiOp)
- defer closer.Close()
- g.ResponseWriter.Write(apiOp, code, obj)
-}
-
-func (g *GzipWriter) WriteList(apiOp *types.APIRequest, code int, obj types.APIObjectList) {
- apiOp, closer := setup(apiOp)
- defer closer.Close()
- g.ResponseWriter.WriteList(apiOp, code, obj)
-}
-
-type gzipResponseWriter struct {
- io.Writer
- http.ResponseWriter
-}
-
-func (g gzipResponseWriter) Write(b []byte) (int, error) {
- return g.Writer.Write(b)
-}
diff --git a/pkg/schemaserver/writer/headers.go b/pkg/schemaserver/writer/headers.go
deleted file mode 100644
index 314dd5e..0000000
--- a/pkg/schemaserver/writer/headers.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package writer
-
-import (
- "github.com/rancher/steve/pkg/schemaserver/types"
-)
-
-func AddCommonResponseHeader(apiOp *types.APIRequest) error {
- addExpires(apiOp)
- return addSchemasHeader(apiOp)
-}
-
-func addSchemasHeader(apiOp *types.APIRequest) error {
- schema := apiOp.Schemas.Schemas["schema"]
- if schema == nil {
- return nil
- }
-
- apiOp.Response.Header().Set("X-Api-Schemas", apiOp.URLBuilder.Collection(schema))
- return nil
-}
-
-func addExpires(apiOp *types.APIRequest) {
- apiOp.Response.Header().Set("Expires", "Wed 24 Feb 1982 18:42:00 GMT")
-}
diff --git a/pkg/schemaserver/writer/html.go b/pkg/schemaserver/writer/html.go
deleted file mode 100644
index 833f59c..0000000
--- a/pkg/schemaserver/writer/html.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package writer
-
-import (
- "strings"
-
- "github.com/rancher/steve/pkg/schemaserver/types"
-)
-
-const (
- JSURL = "https://releases.rancher.com/api-ui/%API_UI_VERSION%/ui.min.js"
- CSSURL = "https://releases.rancher.com/api-ui/%API_UI_VERSION%/ui.min.css"
- DefaultVersion = "1.1.8"
-)
-
-var (
- start = `
-
-
-
-
-
-`)
-)
-
-type StringGetter func() string
-
-type HTMLResponseWriter struct {
- EncodingResponseWriter
- CSSURL StringGetter
- JSURL StringGetter
- APIUIVersion StringGetter
-}
-
-func (h *HTMLResponseWriter) start(apiOp *types.APIRequest, code int) {
- AddCommonResponseHeader(apiOp)
- apiOp.Response.Header().Set("content-type", "text/html")
- apiOp.Response.WriteHeader(code)
-}
-
-func (h *HTMLResponseWriter) Write(apiOp *types.APIRequest, code int, obj types.APIObject) {
- h.write(apiOp, code, obj)
-}
-
-func (h *HTMLResponseWriter) WriteList(apiOp *types.APIRequest, code int, list types.APIObjectList) {
- h.write(apiOp, code, list)
-}
-
-func (h *HTMLResponseWriter) write(apiOp *types.APIRequest, code int, obj interface{}) {
- h.start(apiOp, code)
- schemaSchema := apiOp.Schemas.Schemas["schema"]
- headerString := start
- if schemaSchema != nil {
- headerString = strings.Replace(headerString, "%SCHEMAS%", apiOp.URLBuilder.Collection(schemaSchema), 1)
- }
- var jsurl, cssurl string
- if h.CSSURL != nil && h.JSURL != nil && h.CSSURL() != "" && h.JSURL() != "" {
- jsurl = h.JSURL()
- cssurl = h.CSSURL()
- } else if h.APIUIVersion != nil && h.APIUIVersion() != "" {
- jsurl = strings.Replace(JSURL, "%API_UI_VERSION%", h.APIUIVersion(), 1)
- cssurl = strings.Replace(CSSURL, "%API_UI_VERSION%", h.APIUIVersion(), 1)
- } else {
- jsurl = strings.Replace(JSURL, "%API_UI_VERSION%", DefaultVersion, 1)
- cssurl = strings.Replace(CSSURL, "%API_UI_VERSION%", DefaultVersion, 1)
- }
- headerString = strings.Replace(headerString, "%JSURL%", jsurl, 1)
- headerString = strings.Replace(headerString, "%CSSURL%", cssurl, 1)
-
- apiOp.Response.Write([]byte(headerString))
- if apiObj, ok := obj.(types.APIObject); ok {
- h.Body(apiOp, apiOp.Response, apiObj)
- } else if list, ok := obj.(types.APIObjectList); ok {
- h.BodyList(apiOp, apiOp.Response, list)
- }
- if schemaSchema != nil {
- apiOp.Response.Write(end)
- }
-}
diff --git a/pkg/server/config.go b/pkg/server/config.go
index 6033f35..b50558c 100644
--- a/pkg/server/config.go
+++ b/pkg/server/config.go
@@ -5,11 +5,11 @@ import (
"net/http"
"time"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/accesscontrol"
"github.com/rancher/steve/pkg/auth"
"github.com/rancher/steve/pkg/client"
"github.com/rancher/steve/pkg/schema"
- "github.com/rancher/steve/pkg/schemaserver/types"
"github.com/rancher/steve/pkg/server/router"
"github.com/rancher/wrangler-api/pkg/generated/controllers/apiextensions.k8s.io"
apiextensionsv1beta1 "github.com/rancher/wrangler-api/pkg/generated/controllers/apiextensions.k8s.io/v1beta1"
diff --git a/pkg/server/handler/apiserver.go b/pkg/server/handler/apiserver.go
index 5bb5f1c..2b5f07e 100644
--- a/pkg/server/handler/apiserver.go
+++ b/pkg/server/handler/apiserver.go
@@ -3,13 +3,13 @@ package handler
import (
"net/http"
+ "github.com/rancher/apiserver/pkg/server"
+ "github.com/rancher/apiserver/pkg/types"
+ "github.com/rancher/apiserver/pkg/urlbuilder"
"github.com/rancher/steve/pkg/accesscontrol"
"github.com/rancher/steve/pkg/auth"
k8sproxy "github.com/rancher/steve/pkg/proxy"
"github.com/rancher/steve/pkg/schema"
- "github.com/rancher/steve/pkg/schemaserver/server"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/steve/pkg/schemaserver/urlbuilder"
"github.com/rancher/steve/pkg/server/router"
"github.com/sirupsen/logrus"
"k8s.io/apiserver/pkg/endpoints/request"
diff --git a/pkg/server/handler/handlers.go b/pkg/server/handler/handlers.go
index eb66bc5..0b4fa3e 100644
--- a/pkg/server/handler/handlers.go
+++ b/pkg/server/handler/handlers.go
@@ -2,9 +2,9 @@ package handler
import (
"github.com/gorilla/mux"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/attributes"
"github.com/rancher/steve/pkg/schema"
- "github.com/rancher/steve/pkg/schemaserver/types"
)
func k8sAPI(sf schema.Factory, apiOp *types.APIRequest) {
diff --git a/pkg/server/router/router.go b/pkg/server/router/router.go
index 86158bf..a9c2880 100644
--- a/pkg/server/router/router.go
+++ b/pkg/server/router/router.go
@@ -4,7 +4,7 @@ import (
"net/http"
"github.com/gorilla/mux"
- "github.com/rancher/steve/pkg/schemaserver/urlbuilder"
+ "github.com/rancher/apiserver/pkg/urlbuilder"
)
type RouterFunc func(h Handlers) http.Handler
diff --git a/pkg/server/server.go b/pkg/server/server.go
index 2777897..bfb0e97 100644
--- a/pkg/server/server.go
+++ b/pkg/server/server.go
@@ -5,18 +5,18 @@ import (
"errors"
"net/http"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/dynamiclistener/server"
"github.com/rancher/steve/pkg/accesscontrol"
"github.com/rancher/steve/pkg/client"
"github.com/rancher/steve/pkg/clustercache"
schemacontroller "github.com/rancher/steve/pkg/controllers/schema"
"github.com/rancher/steve/pkg/dashboard"
+ "github.com/rancher/steve/pkg/resources"
+ "github.com/rancher/steve/pkg/resources/common"
+ "github.com/rancher/steve/pkg/resources/schemas"
"github.com/rancher/steve/pkg/schema"
- "github.com/rancher/steve/pkg/schemaserver/types"
"github.com/rancher/steve/pkg/server/handler"
- "github.com/rancher/steve/pkg/server/resources"
- "github.com/rancher/steve/pkg/server/resources/common"
- "github.com/rancher/steve/pkg/server/resources/schemas"
)
var ErrConfigRequired = errors.New("rest config is required")
diff --git a/pkg/server/store/partition/parallel.go b/pkg/stores/partition/parallel.go
similarity index 98%
rename from pkg/server/store/partition/parallel.go
rename to pkg/stores/partition/parallel.go
index bbf1ea5..e1901d3 100644
--- a/pkg/server/store/partition/parallel.go
+++ b/pkg/stores/partition/parallel.go
@@ -5,7 +5,7 @@ import (
"encoding/base64"
"encoding/json"
- "github.com/rancher/steve/pkg/schemaserver/types"
+ "github.com/rancher/apiserver/pkg/types"
"golang.org/x/sync/errgroup"
"golang.org/x/sync/semaphore"
)
diff --git a/pkg/server/store/partition/store.go b/pkg/stores/partition/store.go
similarity index 98%
rename from pkg/server/store/partition/store.go
rename to pkg/stores/partition/store.go
index cac1113..3d5fb57 100644
--- a/pkg/server/store/partition/store.go
+++ b/pkg/stores/partition/store.go
@@ -5,7 +5,7 @@ import (
"net/http"
"strconv"
- "github.com/rancher/steve/pkg/schemaserver/types"
+ "github.com/rancher/apiserver/pkg/types"
"golang.org/x/sync/errgroup"
)
diff --git a/pkg/server/store/proxy/error_wrapper.go b/pkg/stores/proxy/error_wrapper.go
similarity index 91%
rename from pkg/server/store/proxy/error_wrapper.go
rename to pkg/stores/proxy/error_wrapper.go
index 43c2ef1..4aa9fa4 100644
--- a/pkg/server/store/proxy/error_wrapper.go
+++ b/pkg/stores/proxy/error_wrapper.go
@@ -1,8 +1,8 @@
package proxy
import (
- "github.com/rancher/steve/pkg/schemaserver/httperror"
- "github.com/rancher/steve/pkg/schemaserver/types"
+ "github.com/rancher/apiserver/pkg/apierror"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/wrangler/pkg/schemas/validation"
"k8s.io/apimachinery/pkg/api/errors"
)
@@ -47,7 +47,7 @@ func (e *errorStore) Watch(apiOp *types.APIRequest, schema *types.APISchema, wr
func translateError(err error) error {
if apiError, ok := err.(errors.APIStatus); ok {
status := apiError.Status()
- return httperror.NewAPIError(validation.ErrorCode{
+ return apierror.NewAPIError(validation.ErrorCode{
Status: int(status.Code),
Code: string(status.Reason),
}, status.Message)
diff --git a/pkg/server/store/proxy/proxy_store.go b/pkg/stores/proxy/proxy_store.go
similarity index 99%
rename from pkg/server/store/proxy/proxy_store.go
rename to pkg/stores/proxy/proxy_store.go
index 02e188c..babbf43 100644
--- a/pkg/server/store/proxy/proxy_store.go
+++ b/pkg/stores/proxy/proxy_store.go
@@ -10,10 +10,10 @@ import (
"regexp"
"github.com/pkg/errors"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/accesscontrol"
"github.com/rancher/steve/pkg/attributes"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/steve/pkg/server/store/partition"
+ "github.com/rancher/steve/pkg/stores/partition"
"github.com/rancher/wrangler/pkg/data"
"github.com/rancher/wrangler/pkg/schemas/validation"
"github.com/sirupsen/logrus"
diff --git a/pkg/server/store/proxy/rbac_store.go b/pkg/stores/proxy/rbac_store.go
similarity index 97%
rename from pkg/server/store/proxy/rbac_store.go
rename to pkg/stores/proxy/rbac_store.go
index 4878070..dad1a87 100644
--- a/pkg/server/store/proxy/rbac_store.go
+++ b/pkg/stores/proxy/rbac_store.go
@@ -6,10 +6,10 @@ import (
"net/http"
"sort"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/accesscontrol"
"github.com/rancher/steve/pkg/attributes"
- "github.com/rancher/steve/pkg/schemaserver/types"
- "github.com/rancher/steve/pkg/server/store/partition"
+ "github.com/rancher/steve/pkg/stores/partition"
"k8s.io/apimachinery/pkg/util/sets"
)
diff --git a/pkg/server/store/proxy/watch_refresh.go b/pkg/stores/proxy/watch_refresh.go
similarity index 94%
rename from pkg/server/store/proxy/watch_refresh.go
rename to pkg/stores/proxy/watch_refresh.go
index 47fe94d..87ecda0 100644
--- a/pkg/server/store/proxy/watch_refresh.go
+++ b/pkg/stores/proxy/watch_refresh.go
@@ -4,8 +4,8 @@ import (
"context"
"time"
+ "github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/accesscontrol"
- "github.com/rancher/steve/pkg/schemaserver/types"
"k8s.io/apiserver/pkg/endpoints/request"
)
diff --git a/pkg/server/store/selector/selector.go b/pkg/stores/selector/selector.go
similarity index 93%
rename from pkg/server/store/selector/selector.go
rename to pkg/stores/selector/selector.go
index 13ffd99..7298244 100644
--- a/pkg/server/store/selector/selector.go
+++ b/pkg/stores/selector/selector.go
@@ -1,7 +1,7 @@
package selector
import (
- "github.com/rancher/steve/pkg/schemaserver/types"
+ "github.com/rancher/apiserver/pkg/types"
"k8s.io/apimachinery/pkg/labels"
)
diff --git a/pkg/server/store/switchschema/store.go b/pkg/stores/switchschema/store.go
similarity index 97%
rename from pkg/server/store/switchschema/store.go
rename to pkg/stores/switchschema/store.go
index f935f35..0d15731 100644
--- a/pkg/server/store/switchschema/store.go
+++ b/pkg/stores/switchschema/store.go
@@ -1,7 +1,7 @@
package switchschema
import (
- "github.com/rancher/steve/pkg/schemaserver/types"
+ "github.com/rancher/apiserver/pkg/types"
)
type Store struct {
diff --git a/pkg/server/store/switchstore/store.go b/pkg/stores/switchstore/store.go
similarity index 97%
rename from pkg/server/store/switchstore/store.go
rename to pkg/stores/switchstore/store.go
index ed527c8..95dfb31 100644
--- a/pkg/server/store/switchstore/store.go
+++ b/pkg/stores/switchstore/store.go
@@ -1,7 +1,7 @@
package switchstore
import (
- "github.com/rancher/steve/pkg/schemaserver/types"
+ "github.com/rancher/apiserver/pkg/types"
)
type StorePicker func(apiOp *types.APIRequest, schema *types.APISchema, verb, id string) (types.Store, error)