mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +00:00
Bump kube-openapi to add new openapi endpoint
This commit is contained in:
parent
c7414323d8
commit
8b38e080c4
16
Godeps/Godeps.json
generated
16
Godeps/Godeps.json
generated
@ -3265,35 +3265,35 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/aggregator",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/builder",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/common",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/generators",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/handler",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/util",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/util/proto",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/util/proto/validation",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/utils/clock",
|
||||
|
@ -1640,23 +1640,23 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/builder",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/common",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/handler",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/util",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/util/proto",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/apimachinery/pkg/api/equality",
|
||||
|
@ -172,7 +172,7 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/util/proto",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
10
staging/src/k8s.io/apiserver/Godeps/Godeps.json
generated
10
staging/src/k8s.io/apiserver/Godeps/Godeps.json
generated
@ -1736,23 +1736,23 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/builder",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/common",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/handler",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/util",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/util/proto",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/client-go/discovery",
|
||||
|
2
staging/src/k8s.io/client-go/Godeps/Godeps.json
generated
2
staging/src/k8s.io/client-go/Godeps/Godeps.json
generated
@ -612,7 +612,7 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/util/proto",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -260,11 +260,11 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/common",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/generators",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1628,27 +1628,27 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/aggregator",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/builder",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/common",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/handler",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/util",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/util/proto",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1616,23 +1616,23 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/builder",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/common",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/handler",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/util",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/util/proto",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -900,7 +900,7 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/util/proto",
|
||||
"Rev": "a07b7bbb58e7fdc5144f8d7046331d29fc9ad3b3"
|
||||
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
49
vendor/k8s.io/kube-openapi/pkg/aggregator/aggregator.go
generated
vendored
49
vendor/k8s.io/kube-openapi/pkg/aggregator/aggregator.go
generated
vendored
@ -58,8 +58,10 @@ func (s *referenceWalker) walkRef(ref spec.Ref) spec.Ref {
|
||||
// We do not support external references yet.
|
||||
if !s.alreadyVisited[refStr] && strings.HasPrefix(refStr, definitionPrefix) {
|
||||
s.alreadyVisited[refStr] = true
|
||||
def := s.root.Definitions[refStr[len(definitionPrefix):]]
|
||||
k := refStr[len(definitionPrefix):]
|
||||
def := s.root.Definitions[k]
|
||||
s.walkSchema(&def)
|
||||
s.root.Definitions[k] = def
|
||||
}
|
||||
return s.walkRefCallback(ref)
|
||||
}
|
||||
@ -69,23 +71,26 @@ func (s *referenceWalker) walkSchema(schema *spec.Schema) {
|
||||
return
|
||||
}
|
||||
schema.Ref = s.walkRef(schema.Ref)
|
||||
for _, v := range schema.Definitions {
|
||||
for k, v := range schema.Definitions {
|
||||
s.walkSchema(&v)
|
||||
schema.Definitions[k] = v
|
||||
}
|
||||
for _, v := range schema.Properties {
|
||||
for k, v := range schema.Properties {
|
||||
s.walkSchema(&v)
|
||||
schema.Properties[k] = v
|
||||
}
|
||||
for _, v := range schema.PatternProperties {
|
||||
for k, v := range schema.PatternProperties {
|
||||
s.walkSchema(&v)
|
||||
schema.PatternProperties[k] = v
|
||||
}
|
||||
for _, v := range schema.AllOf {
|
||||
s.walkSchema(&v)
|
||||
for i, _ := range schema.AllOf {
|
||||
s.walkSchema(&schema.AllOf[i])
|
||||
}
|
||||
for _, v := range schema.AnyOf {
|
||||
s.walkSchema(&v)
|
||||
for i, _ := range schema.AnyOf {
|
||||
s.walkSchema(&schema.AnyOf[i])
|
||||
}
|
||||
for _, v := range schema.OneOf {
|
||||
s.walkSchema(&v)
|
||||
for i, _ := range schema.OneOf {
|
||||
s.walkSchema(&schema.OneOf[i])
|
||||
}
|
||||
if schema.Not != nil {
|
||||
s.walkSchema(schema.Not)
|
||||
@ -100,8 +105,8 @@ func (s *referenceWalker) walkSchema(schema *spec.Schema) {
|
||||
if schema.Items.Schema != nil {
|
||||
s.walkSchema(schema.Items.Schema)
|
||||
}
|
||||
for _, v := range schema.Items.Schemas {
|
||||
s.walkSchema(&v)
|
||||
for i, _ := range schema.Items.Schemas {
|
||||
s.walkSchema(&schema.Items.Schemas[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -291,15 +296,29 @@ func mergeSpecs(dest, source *spec.Swagger, renameModelConflicts, ignorePathConf
|
||||
from, to string
|
||||
}
|
||||
renames := []Rename{}
|
||||
|
||||
OUTERLOOP:
|
||||
for k, v := range source.Definitions {
|
||||
if usedNames[k] {
|
||||
v2, found := dest.Definitions[k]
|
||||
// Reuse model iff they are exactly the same.
|
||||
// Reuse model if they are exactly the same.
|
||||
if found && reflect.DeepEqual(v, v2) {
|
||||
continue
|
||||
}
|
||||
i := 2
|
||||
newName := fmt.Sprintf("%s_v%d", k, i)
|
||||
|
||||
// Reuse previously renamed model if one exists
|
||||
var newName string
|
||||
i := 1
|
||||
for found {
|
||||
i++
|
||||
newName = fmt.Sprintf("%s_v%d", k, i)
|
||||
v2, found = dest.Definitions[newName]
|
||||
if found && reflect.DeepEqual(v, v2) {
|
||||
renames = append(renames, Rename{from: k, to: newName})
|
||||
continue OUTERLOOP
|
||||
}
|
||||
}
|
||||
|
||||
_, foundInSource := source.Definitions[newName]
|
||||
for usedNames[newName] || foundInSource {
|
||||
i++
|
||||
|
2
vendor/k8s.io/kube-openapi/pkg/generators/openapi.go
generated
vendored
2
vendor/k8s.io/kube-openapi/pkg/generators/openapi.go
generated
vendored
@ -634,6 +634,8 @@ func (g openAPITypeWriter) generateSliceProperty(t *types.Type) error {
|
||||
return fmt.Errorf("please add type %v to getOpenAPITypeFormat function", elemType)
|
||||
case types.Struct:
|
||||
g.generateReferenceProperty(elemType)
|
||||
case types.Slice, types.Array:
|
||||
g.generateSliceProperty(elemType)
|
||||
default:
|
||||
return fmt.Errorf("slice Element kind %v is not supported in %v", elemType.Kind, t)
|
||||
}
|
||||
|
1
vendor/k8s.io/kube-openapi/pkg/handler/BUILD
generated
vendored
1
vendor/k8s.io/kube-openapi/pkg/handler/BUILD
generated
vendored
@ -6,6 +6,7 @@ go_library(
|
||||
importpath = "k8s.io/kube-openapi/pkg/handler",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/bitbucket.org/ww/goautoneg:go_default_library",
|
||||
"//vendor/github.com/NYTimes/gziphandler:go_default_library",
|
||||
"//vendor/github.com/emicklei/go-restful:go_default_library",
|
||||
"//vendor/github.com/go-openapi/spec:go_default_library",
|
||||
|
77
vendor/k8s.io/kube-openapi/pkg/handler/handler.go
generated
vendored
77
vendor/k8s.io/kube-openapi/pkg/handler/handler.go
generated
vendored
@ -22,18 +22,21 @@ import (
|
||||
"crypto/sha512"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"gopkg.in/yaml.v2"
|
||||
"mime"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"bitbucket.org/ww/goautoneg"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/NYTimes/gziphandler"
|
||||
"github.com/emicklei/go-restful"
|
||||
restful "github.com/emicklei/go-restful"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/googleapis/gnostic/OpenAPIv2"
|
||||
openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2"
|
||||
"github.com/googleapis/gnostic/compiler"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/builder"
|
||||
@ -77,6 +80,10 @@ func computeETag(data []byte) string {
|
||||
return fmt.Sprintf("\"%X\"", sha512.Sum512(data))
|
||||
}
|
||||
|
||||
// NOTE: [DEPRECATION] We will announce deprecation for format-separated endpoints for OpenAPI spec,
|
||||
// and switch to a single /openapi/v2 endpoint in Kubernetes 1.10. The design doc and deprecation process
|
||||
// are tracked at: https://docs.google.com/document/d/19lEqE9lc4yHJ3WJAJxS_G7TcORIJXGHyq3wpwcH28nU.
|
||||
//
|
||||
// BuildAndRegisterOpenAPIService builds the spec and registers a handler to provides access to it.
|
||||
// Use this method if your OpenAPI spec is static. If you want to update the spec, use BuildOpenAPISpec then RegisterOpenAPIService.
|
||||
func BuildAndRegisterOpenAPIService(servePath string, webServices []*restful.WebService, config *common.Config, handler common.PathHandler) (*OpenAPIService, error) {
|
||||
@ -87,6 +94,10 @@ func BuildAndRegisterOpenAPIService(servePath string, webServices []*restful.Web
|
||||
return RegisterOpenAPIService(spec, servePath, handler)
|
||||
}
|
||||
|
||||
// NOTE: [DEPRECATION] We will announce deprecation for format-separated endpoints for OpenAPI spec,
|
||||
// and switch to a single /openapi/v2 endpoint in Kubernetes 1.10. The design doc and deprecation process
|
||||
// are tracked at: https://docs.google.com/document/d/19lEqE9lc4yHJ3WJAJxS_G7TcORIJXGHyq3wpwcH28nU.
|
||||
//
|
||||
// RegisterOpenAPIService registers a handler to provides access to provided swagger spec.
|
||||
// Note: servePath should end with ".json" as the RegisterOpenAPIService assume it is serving a
|
||||
// json file and will also serve .pb and .gz files.
|
||||
@ -202,3 +213,63 @@ func toGzip(data []byte) []byte {
|
||||
zw.Close()
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// RegisterOpenAPIVersionedService registers a handler to provides access to provided swagger spec.
|
||||
func RegisterOpenAPIVersionedService(openapiSpec *spec.Swagger, servePath string, handler common.PathHandler) (*OpenAPIService, error) {
|
||||
o := OpenAPIService{}
|
||||
if err := o.UpdateSpec(openapiSpec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accepted := []struct {
|
||||
Type string
|
||||
SubType string
|
||||
GetDataAndETag func() ([]byte, string, time.Time)
|
||||
}{
|
||||
{"application", "json", o.getSwaggerBytes},
|
||||
{"application", "com.github.proto-openapi.spec.v2@v1.0+protobuf", o.getSwaggerPbBytes},
|
||||
}
|
||||
|
||||
handler.Handle(servePath, gziphandler.GzipHandler(http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
decipherableFormats := r.Header.Get("Accept")
|
||||
if decipherableFormats == "" {
|
||||
decipherableFormats = "*/*"
|
||||
}
|
||||
clauses := goautoneg.ParseAccept(decipherableFormats)
|
||||
w.Header().Add("Vary", "Accept")
|
||||
for _, clause := range clauses {
|
||||
for _, accepts := range accepted {
|
||||
if clause.Type != accepts.Type && clause.Type != "*" {
|
||||
continue
|
||||
}
|
||||
if clause.SubType != accepts.SubType && clause.SubType != "*" {
|
||||
continue
|
||||
}
|
||||
|
||||
// serve the first matching media type in the sorted clause list
|
||||
data, etag, lastModified := accepts.GetDataAndETag()
|
||||
w.Header().Set("Etag", etag)
|
||||
// ServeContent will take care of caching using eTag.
|
||||
http.ServeContent(w, r, servePath, lastModified, bytes.NewReader(data))
|
||||
return
|
||||
}
|
||||
}
|
||||
// Return 406 for not acceptable format
|
||||
w.WriteHeader(406)
|
||||
return
|
||||
}),
|
||||
))
|
||||
|
||||
return &o, nil
|
||||
}
|
||||
|
||||
// BuildAndRegisterOpenAPIVersionedService builds the spec and registers a handler to provides access to it.
|
||||
// Use this method if your OpenAPI spec is static. If you want to update the spec, use BuildOpenAPISpec then RegisterOpenAPIVersionedService.
|
||||
func BuildAndRegisterOpenAPIVersionedService(servePath string, webServices []*restful.WebService, config *common.Config, handler common.PathHandler) (*OpenAPIService, error) {
|
||||
spec, err := builder.BuildOpenAPISpec(webServices, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return RegisterOpenAPIVersionedService(spec, servePath, handler)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user