mirror of https://github.com/k3s-io/k3s
- Add GroupVersion as tags to OpenAPI spec
- Remove all end-point specs as they are not useful in light of GroupVersion tags in main specpull/6/head
parent
8ff18565b8
commit
75451b49f4
|
@ -387,60 +387,6 @@ kube::util::fetch-swagger-spec() {
|
|||
curl -w "\n" -fs "${SWAGGER_API_PATH}logs" > "${SWAGGER_ROOT_DIR}/logs.json"
|
||||
}
|
||||
|
||||
# Takes a group/version and returns the openapi-spec file name.
|
||||
# default behavior: extensions/v1beta1 -> v1beta1.extensions
|
||||
# special case for v1: v1 -> v1
|
||||
kube::util::gv-to-openapi-name() {
|
||||
local group_version="$1"
|
||||
case "${group_version}" in
|
||||
v1)
|
||||
echo "v1"
|
||||
;;
|
||||
*)
|
||||
echo "${group_version#*/}.${group_version%/*}"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
||||
# Fetches openapi spec from apiserver.
|
||||
# Assumed vars:
|
||||
# OPENAPI_API_PATH: Base path for openapi on apiserver. normally APIServer root. i.e., http://localhost:8080/
|
||||
# OPENAPI_ROOT_DIR: Root dir where we want to to save the fetched spec.
|
||||
# VERSIONS: Array of group versions to include in swagger spec.
|
||||
kube::util::fetch-openapi-spec() {
|
||||
for ver in ${VERSIONS}; do
|
||||
if [[ " ${KUBE_NONSERVER_GROUP_VERSIONS} " == *" ${ver} "* ]]; then
|
||||
continue
|
||||
fi
|
||||
# fetch the openapi spec for each group version.
|
||||
if [[ ${ver} == "v1" ]]; then
|
||||
SUBPATH="api"
|
||||
else
|
||||
SUBPATH="apis"
|
||||
fi
|
||||
SUBPATH="${SUBPATH}/${ver}"
|
||||
OPENAPI_JSON_NAME="$(kube::util::gv-to-openapi-name ${ver}).json"
|
||||
curl -w "\n" -fs "${OPENAPI_PATH}${SUBPATH}/swagger.json" > "${OPENAPI_ROOT_DIR}/${OPENAPI_JSON_NAME}"
|
||||
|
||||
# fetch the openapi spec for the discovery mechanism at group level.
|
||||
if [[ ${ver} == "v1" ]]; then
|
||||
continue
|
||||
fi
|
||||
SUBPATH="apis/"${ver%/*}
|
||||
OPENAPI_JSON_NAME="${ver%/*}.json"
|
||||
curl -w "\n" -fs "${OPENAPI_PATH}${SUBPATH}/swagger.json" > "${OPENAPI_ROOT_DIR}/${OPENAPI_JSON_NAME}"
|
||||
done
|
||||
|
||||
# fetch openapi specs for other discovery mechanism.
|
||||
curl -w "\n" -fs "${OPENAPI_PATH}swagger.json" > "${OPENAPI_ROOT_DIR}/root_swagger.json"
|
||||
curl -w "\n" -fs "${OPENAPI_PATH}version/swagger.json" > "${OPENAPI_ROOT_DIR}/version.json"
|
||||
curl -w "\n" -fs "${OPENAPI_PATH}api/swagger.json" > "${OPENAPI_ROOT_DIR}/api.json"
|
||||
curl -w "\n" -fs "${OPENAPI_PATH}apis/swagger.json" > "${OPENAPI_ROOT_DIR}/apis.json"
|
||||
curl -w "\n" -fs "${OPENAPI_PATH}logs/swagger.json" > "${OPENAPI_ROOT_DIR}/logs.json"
|
||||
}
|
||||
|
||||
|
||||
# Returns the name of the upstream remote repository name for the local git
|
||||
# repo, e.g. "upstream" or "origin".
|
||||
kube::util::git_upstream_remote_name() {
|
||||
|
|
|
@ -60,18 +60,15 @@ kube::log::status "Starting federation-apiserver"
|
|||
--insecure-port="${API_PORT}" \
|
||||
--etcd-servers="http://${ETCD_HOST}:${ETCD_PORT}" \
|
||||
--advertise-address="10.10.10.10" \
|
||||
--cert-dir="${TMP_DIR}/certs" \
|
||||
--token-auth-file=$TMP_DIR/tokenauth.csv \
|
||||
--service-cluster-ip-range="10.0.0.0/24" >/tmp/openapi-federation-api-server.log 2>&1 &
|
||||
APISERVER_PID=$!
|
||||
kube::util::wait_for_url "${API_HOST}:${API_PORT}/" "apiserver: "
|
||||
|
||||
OPENAPI_PATH="${API_HOST}:${API_PORT}/"
|
||||
DEFAULT_GROUP_VERSIONS="v1 extensions/v1beta1 federation/v1beta1"
|
||||
VERSIONS=${VERSIONS:-$DEFAULT_GROUP_VERSIONS}
|
||||
|
||||
kube::log::status "Updating " ${OPENAPI_ROOT_DIR}
|
||||
|
||||
OPENAPI_PATH="${OPENAPI_PATH}" OPENAPI_ROOT_DIR="${OPENAPI_ROOT_DIR}" VERSIONS="${VERSIONS}" kube::util::fetch-openapi-spec
|
||||
curl -w "\n" -fs "${API_HOST}:${API_PORT}/swagger.json" > "${OPENAPI_ROOT_DIR}/swagger.json"
|
||||
|
||||
kube::log::status "SUCCESS"
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ kube::util::wait_for_url "${API_HOST}:${API_PORT}/healthz" "apiserver: "
|
|||
|
||||
kube::log::status "Updating " ${OPENAPI_ROOT_DIR}
|
||||
|
||||
OPENAPI_PATH="${API_HOST}:${API_PORT}/" OPENAPI_ROOT_DIR="${OPENAPI_ROOT_DIR}" VERSIONS="${KUBE_AVAILABLE_GROUP_VERSIONS}" KUBE_NONSERVER_GROUP_VERSIONS="${KUBE_NONSERVER_GROUP_VERSIONS}" kube::util::fetch-openapi-spec
|
||||
curl -w "\n" -fs "${API_HOST}:${API_PORT}/swagger.json" > "${OPENAPI_ROOT_DIR}/swagger.json"
|
||||
|
||||
kube::log::status "SUCCESS"
|
||||
|
||||
|
|
|
@ -48,10 +48,11 @@ func ToValidOperationID(s string, capitalizeFirstLetter bool) string {
|
|||
return buffer.String()
|
||||
}
|
||||
|
||||
// GetOperationID returns a customize operation ID for kubernetes API server's OpenAPI spec to prevent duplicate IDs.
|
||||
func GetOperationID(servePath string, r *restful.Route) (string, error) {
|
||||
// GetOperationIDAndTags returns a customize operation ID and a list of tags for kubernetes API server's OpenAPI spec to prevent duplicate IDs.
|
||||
func GetOperationIDAndTags(servePath string, r *restful.Route) (string, []string, error) {
|
||||
op := r.Operation
|
||||
path := r.Path
|
||||
var tags []string
|
||||
// TODO: This is hacky, figure out where this name conflict is created and fix it at the root.
|
||||
if strings.HasPrefix(path, "/apis/extensions/v1beta1/namespaces/{namespace}/") && strings.HasSuffix(op, "ScaleScale") {
|
||||
op = op[:len(op)-10] + strings.Title(strings.Split(path[48:], "/")[0]) + "Scale"
|
||||
|
@ -60,7 +61,7 @@ func GetOperationID(servePath string, r *restful.Route) (string, error) {
|
|||
case "/swagger.json":
|
||||
prefix, exists := verbs.GetPrefix(op)
|
||||
if !exists {
|
||||
return op, fmt.Errorf("operation names should start with a verb. Cannot determine operation verb from %v", op)
|
||||
return op, tags, fmt.Errorf("operation names should start with a verb. Cannot determine operation verb from %v", op)
|
||||
}
|
||||
op = op[len(prefix):]
|
||||
parts := strings.Split(strings.Trim(path, "/"), "/")
|
||||
|
@ -70,12 +71,17 @@ func GetOperationID(servePath string, r *restful.Route) (string, error) {
|
|||
}
|
||||
if len(parts) >= 2 && parts[0] == "apis" {
|
||||
prefix = prefix + ToValidOperationID(strings.TrimSuffix(parts[1], ".k8s.io"), prefix != "")
|
||||
tag := ToValidOperationID(strings.TrimSuffix(parts[1], ".k8s.io"), false)
|
||||
if len(parts) > 2 {
|
||||
prefix = prefix + ToValidOperationID(parts[2], prefix != "")
|
||||
tag = tag + "_" + ToValidOperationID(parts[2], false)
|
||||
}
|
||||
tags = append(tags, tag)
|
||||
} else if len(parts) >= 1 {
|
||||
tags = append(tags, ToValidOperationID(parts[0], false))
|
||||
}
|
||||
return prefix + ToValidOperationID(op, prefix != ""), nil
|
||||
return prefix + ToValidOperationID(op, prefix != ""), tags, nil
|
||||
default:
|
||||
return op, nil
|
||||
return op, tags, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -223,7 +223,7 @@ func NewConfig() *Config {
|
|||
Description: "Default Response.",
|
||||
},
|
||||
},
|
||||
GetOperationID: apiserveropenapi.GetOperationID,
|
||||
GetOperationIDAndTags: apiserveropenapi.GetOperationIDAndTags,
|
||||
},
|
||||
LongRunningFunc: genericfilters.BasicLongRunningRequestCheck(longRunningRE, map[string]string{"watch": "true"}),
|
||||
}
|
||||
|
|
|
@ -61,8 +61,8 @@ type Config struct {
|
|||
// or any of the models will result in spec generation failure.
|
||||
Definitions *OpenAPIDefinitions
|
||||
|
||||
// GetOperationID returns operation id for a restful route. It is an optional function to customize operation IDs.
|
||||
GetOperationID func(servePath string, r *restful.Route) (string, error)
|
||||
// GetOperationIDAndTags returns operation id and tags for a restful route. It is an optional function to customize operation IDs.
|
||||
GetOperationIDAndTags func(servePath string, r *restful.Route) (string, []string, error)
|
||||
|
||||
// SecurityDefinitions is list of all security definitions for OpenAPI service. If this is not nil, the user of config
|
||||
// is responsible to provide DefaultSecurity and (maybe) add unauthorized response to CommonResponses.
|
||||
|
|
|
@ -74,9 +74,9 @@ func RegisterOpenAPIService(servePath string, webServices []*restful.WebService,
|
|||
}
|
||||
|
||||
func (o *openAPI) init(webServices []*restful.WebService) error {
|
||||
if o.config.GetOperationID == nil {
|
||||
o.config.GetOperationID = func(_ string, r *restful.Route) (string, error) {
|
||||
return r.Operation, nil
|
||||
if o.config.GetOperationIDAndTags == nil {
|
||||
o.config.GetOperationIDAndTags = func(_ string, r *restful.Route) (string, []string, error) {
|
||||
return r.Operation, nil, nil
|
||||
}
|
||||
}
|
||||
if o.config.CommonResponses == nil {
|
||||
|
@ -217,7 +217,7 @@ func (o *openAPI) buildOperations(route restful.Route, inPathCommonParamsMap map
|
|||
},
|
||||
},
|
||||
}
|
||||
if ret.ID, err = o.config.GetOperationID(o.servePath, &route); err != nil {
|
||||
if ret.ID, ret.Tags, err = o.config.GetOperationIDAndTags(o.servePath, &route); err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ go_library(
|
|||
"//vendor:github.com/elazarl/go-bindata-assetfs",
|
||||
"//vendor:github.com/emicklei/go-restful",
|
||||
"//vendor:github.com/emicklei/go-restful/swagger",
|
||||
"//vendor:github.com/go-openapi/spec",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -17,14 +17,10 @@ limitations under the License.
|
|||
package routes
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/genericapiserver/mux"
|
||||
"k8s.io/kubernetes/pkg/genericapiserver/openapi"
|
||||
"k8s.io/kubernetes/pkg/genericapiserver/openapi/common"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
|
@ -35,22 +31,6 @@ type OpenAPI struct {
|
|||
|
||||
// Install adds the SwaggerUI webservice to the given mux.
|
||||
func (oa OpenAPI) Install(c *mux.APIContainer) {
|
||||
// Install one spec per web service, an ideal client will have a ClientSet containing one client
|
||||
// per each of these specs.
|
||||
for _, w := range c.RegisteredWebServices() {
|
||||
if strings.HasPrefix(w.RootPath(), "/swaggerapi") {
|
||||
continue
|
||||
}
|
||||
|
||||
config := *oa.Config
|
||||
config.Info = new(spec.Info)
|
||||
*config.Info = *oa.Config.Info
|
||||
config.Info.Title = config.Info.Title + " " + w.RootPath()
|
||||
err := openapi.RegisterOpenAPIService(w.RootPath()+"/swagger.json", []*restful.WebService{w}, &config, c)
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to register open api spec for %v: %v", w.RootPath(), err)
|
||||
}
|
||||
}
|
||||
err := openapi.RegisterOpenAPIService("/swagger.json", c.RegisteredWebServices(), oa.Config, c)
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to register open api spec for root: %v", err)
|
||||
|
|
|
@ -24,7 +24,6 @@ import (
|
|||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
|
@ -519,10 +518,6 @@ func TestValidOpenAPISpec(t *testing.T) {
|
|||
// TODO(mehdy): The actual validation part of these tests are timing out on jerkin but passing locally. Enable it after debugging timeout issue.
|
||||
disableValidation := true
|
||||
|
||||
// Saving specs to a temporary folder is a good way to debug spec generation without bringing up an actual
|
||||
// api server.
|
||||
saveSwaggerSpecs := false
|
||||
|
||||
// Validate OpenApi spec
|
||||
doc, err := loads.Spec(server.URL + "/swagger.json")
|
||||
if assert.NoError(err) {
|
||||
|
@ -537,46 +532,4 @@ func TestValidOpenAPISpec(t *testing.T) {
|
|||
t.Logf("Validation is disabled because it is timing out on jenkins put passing locally.")
|
||||
}
|
||||
}
|
||||
|
||||
// validate specs on each end-point
|
||||
resp, err = http.Get(server.URL)
|
||||
if !assert.NoError(err) {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
assert.Equal(http.StatusOK, resp.StatusCode)
|
||||
var list unversioned.RootPaths
|
||||
if assert.NoError(decodeResponse(resp, &list)) {
|
||||
for _, path := range list.Paths {
|
||||
if !strings.HasPrefix(path, "/api") {
|
||||
continue
|
||||
}
|
||||
t.Logf("Validating open API spec on %v ...", path)
|
||||
|
||||
if saveSwaggerSpecs {
|
||||
resp, err = http.Get(server.URL + path + "/swagger.json")
|
||||
if !assert.NoError(err) {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
assert.Equal(http.StatusOK, resp.StatusCode)
|
||||
assert.NoError(writeResponseToFile(resp, "/tmp/swagger_"+strings.Replace(path, "/", "_", -1)+".json"))
|
||||
}
|
||||
|
||||
// Validate OpenApi spec on path
|
||||
doc, err := loads.Spec(server.URL + path + "/swagger.json")
|
||||
if assert.NoError(err) {
|
||||
validator := validate.NewSpecValidator(doc.Schema(), strfmt.Default)
|
||||
if !disableValidation {
|
||||
res, warns := validator.Validate(doc)
|
||||
assert.NoError(res.AsError())
|
||||
if !warns.IsValid() {
|
||||
t.Logf("Open API spec on %v has some warnings : %v", path, warns)
|
||||
}
|
||||
} else {
|
||||
t.Logf("Validation is disabled because it is timing out on jenkins but passing locally.")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue