From c77d3b51bef1b03bee6c672f621b235e9a14de67 Mon Sep 17 00:00:00 2001 From: galal-hussein Date: Tue, 28 Nov 2017 19:44:55 +0200 Subject: [PATCH 1/2] Vendor Update --- .../rancher/norman/clientbase/common.go | 14 +- .../norman/clientbase/object_client.go | 21 ++- .../rancher/norman/clientbase/ops.go | 46 +++--- .../norman/controller/generic_controller.go | 8 +- .../rancher/norman/types/condition.go | 142 +++++++++--------- .../rancher/norman/types/convert/convert.go | 4 +- .../rancher/norman/types/convert/ref.go | 11 ++ .../norman/types/convert/value_set_string.go | 3 +- .../github.com/rancher/norman/types/mapper.go | 64 +++++--- .../rancher/norman/types/reflection.go | 115 ++++++++++++-- .../rancher/norman/types/schema_funcs.go | 26 ++++ .../rancher/norman/types/schemas.go | 58 ++++--- .../rancher/norman/types/server_types.go | 82 +++++++--- .../rancher/norman/types/slice/contains.go | 10 ++ .../github.com/rancher/norman/types/types.go | 29 +++- .../types/apis/cluster.cattle.io/v1/types.go | 20 +-- .../v1/zz_generated_cluster_controller.go | 2 +- .../zz_generated_cluster_node_controller.go | 2 +- .../v1/zz_generated_deepcopy.go | 14 +- vendor/github.com/rancher/types/vendor.conf | 2 +- 20 files changed, 461 insertions(+), 212 deletions(-) create mode 100644 vendor/github.com/rancher/norman/types/convert/ref.go create mode 100644 vendor/github.com/rancher/norman/types/schema_funcs.go create mode 100644 vendor/github.com/rancher/norman/types/slice/contains.go diff --git a/vendor/github.com/rancher/norman/clientbase/common.go b/vendor/github.com/rancher/norman/clientbase/common.go index 16fa88d3f..11cd3de94 100644 --- a/vendor/github.com/rancher/norman/clientbase/common.go +++ b/vendor/github.com/rancher/norman/clientbase/common.go @@ -55,7 +55,7 @@ func IsNotFound(err error) bool { return apiError.StatusCode == http.StatusNotFound } -func newApiError(resp *http.Response, url string) *APIError { +func newAPIError(resp *http.Response, url string) *APIError { contents, err := ioutil.ReadAll(resp.Body) var body string if err != nil { @@ -161,7 +161,7 @@ func NewAPIClient(opts *ClientOpts) (APIBaseClient, error) { defer resp.Body.Close() if resp.StatusCode != 200 { - return result, newApiError(resp, opts.URL) + return result, newAPIError(resp, opts.URL) } schemasURLs := resp.Header.Get("X-API-Schemas") @@ -184,7 +184,7 @@ func NewAPIClient(opts *ClientOpts) (APIBaseClient, error) { defer resp.Body.Close() if resp.StatusCode != 200 { - return result, newApiError(resp, opts.URL) + return result, newAPIError(resp, opts.URL) } } @@ -244,7 +244,7 @@ func (a *APIBaseClient) Post(url string, createObj interface{}, respObject inter func (a *APIBaseClient) GetLink(resource types.Resource, link string, respObject interface{}) error { url := resource.Links[link] if url == "" { - return fmt.Errorf("Failed to find link: %s", link) + return fmt.Errorf("failed to find link: %s", link) } return a.Ops.DoGet(url, &types.ListOpts{}, respObject) @@ -270,12 +270,12 @@ func (a *APIBaseClient) Delete(existing *types.Resource) error { } func (a *APIBaseClient) Reload(existing *types.Resource, output interface{}) error { - selfUrl, ok := existing.Links[SELF] + selfURL, ok := existing.Links[SELF] if !ok { - return errors.New(fmt.Sprintf("Failed to find self URL of [%v]", existing)) + return fmt.Errorf("failed to find self URL of [%v]", existing) } - return a.Ops.DoGet(selfUrl, NewListOpts(), output) + return a.Ops.DoGet(selfURL, NewListOpts(), output) } func (a *APIBaseClient) Action(schemaType string, action string, diff --git a/vendor/github.com/rancher/norman/clientbase/object_client.go b/vendor/github.com/rancher/norman/clientbase/object_client.go index 234434780..9b45700e6 100644 --- a/vendor/github.com/rancher/norman/clientbase/object_client.go +++ b/vendor/github.com/rancher/norman/clientbase/object_client.go @@ -35,6 +35,13 @@ func NewObjectClient(namespace string, restClient rest.Interface, apiResource *m } } +func (p *ObjectClient) getAPIPrefix() string { + if p.gvk.Group == "" { + return "api" + } + return "apis" +} + func (p *ObjectClient) Create(o runtime.Object) (runtime.Object, error) { ns := p.ns if obj, ok := o.(metav1.Object); ok && obj.GetNamespace() != "" { @@ -42,7 +49,7 @@ func (p *ObjectClient) Create(o runtime.Object) (runtime.Object, error) { } result := p.Factory.Object() err := p.restClient.Post(). - Prefix("apis", p.gvk.Group, p.gvk.Version). + Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version). NamespaceIfScoped(ns, p.resource.Namespaced). Resource(p.resource.Name). Body(o). @@ -54,7 +61,7 @@ func (p *ObjectClient) Create(o runtime.Object) (runtime.Object, error) { func (p *ObjectClient) Get(name string, opts metav1.GetOptions) (runtime.Object, error) { result := p.Factory.Object() err := p.restClient.Get(). - Prefix("apis", p.gvk.Group, p.gvk.Version). + Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version). NamespaceIfScoped(p.ns, p.resource.Namespaced). Resource(p.resource.Name). VersionedParams(&opts, dynamic.VersionedParameterEncoderWithV1Fallback). @@ -74,7 +81,7 @@ func (p *ObjectClient) Update(name string, o runtime.Object) (runtime.Object, er return result, errors.New("object missing name") } err := p.restClient.Put(). - Prefix("apis", p.gvk.Group, p.gvk.Version). + Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version). NamespaceIfScoped(ns, p.resource.Namespaced). Resource(p.resource.Name). Name(name). @@ -86,7 +93,7 @@ func (p *ObjectClient) Update(name string, o runtime.Object) (runtime.Object, er func (p *ObjectClient) Delete(name string, opts *metav1.DeleteOptions) error { return p.restClient.Delete(). - Prefix("apis", p.gvk.Group, p.gvk.Version). + Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version). NamespaceIfScoped(p.ns, p.resource.Namespaced). Resource(p.resource.Name). Name(name). @@ -98,7 +105,7 @@ func (p *ObjectClient) Delete(name string, opts *metav1.DeleteOptions) error { func (p *ObjectClient) List(opts metav1.ListOptions) (runtime.Object, error) { result := p.Factory.List() return result, p.restClient.Get(). - Prefix("apis", p.gvk.Group, p.gvk.Version). + Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version). NamespaceIfScoped(p.ns, p.resource.Namespaced). Resource(p.resource.Name). VersionedParams(&opts, dynamic.VersionedParameterEncoderWithV1Fallback). @@ -108,7 +115,7 @@ func (p *ObjectClient) List(opts metav1.ListOptions) (runtime.Object, error) { func (p *ObjectClient) Watch(opts metav1.ListOptions) (watch.Interface, error) { r, err := p.restClient.Get(). - Prefix("apis", p.gvk.Group, p.gvk.Version). + Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version). Prefix("watch"). Namespace(p.ns). NamespaceIfScoped(p.ns, p.resource.Namespaced). @@ -127,7 +134,7 @@ func (p *ObjectClient) Watch(opts metav1.ListOptions) (watch.Interface, error) { func (p *ObjectClient) DeleteCollection(deleteOptions *metav1.DeleteOptions, listOptions metav1.ListOptions) error { return p.restClient.Delete(). - Prefix("apis", p.gvk.Group, p.gvk.Version). + Prefix(p.getAPIPrefix(), p.gvk.Group, p.gvk.Version). NamespaceIfScoped(p.ns, p.resource.Namespaced). Resource(p.resource.Name). VersionedParams(&listOptions, dynamic.VersionedParameterEncoderWithV1Fallback). diff --git a/vendor/github.com/rancher/norman/clientbase/ops.go b/vendor/github.com/rancher/norman/clientbase/ops.go index 0a9fd93e0..d60e6c150 100644 --- a/vendor/github.com/rancher/norman/clientbase/ops.go +++ b/vendor/github.com/rancher/norman/clientbase/ops.go @@ -34,7 +34,7 @@ func (a *APIOperations) DoDelete(url string) error { io.Copy(ioutil.Discard, resp.Body) if resp.StatusCode >= 300 { - return newApiError(resp, url) + return newAPIError(resp, url) } return nil @@ -68,7 +68,7 @@ func (a *APIOperations) DoGet(url string, opts *types.ListOpts, respObject inter defer resp.Body.Close() if resp.StatusCode != 200 { - return newApiError(resp, url) + return newAPIError(resp, url) } byteContent, err := ioutil.ReadAll(resp.Body) @@ -97,16 +97,16 @@ func (a *APIOperations) DoList(schemaType string, opts *types.ListOpts, respObje return errors.New("Resource type [" + schemaType + "] is not listable") } - collectionUrl, ok := schema.Links[COLLECTION] + collectionURL, ok := schema.Links[COLLECTION] if !ok { return errors.New("Failed to find collection URL for [" + schemaType + "]") } - return a.DoGet(collectionUrl, opts, respObject) + return a.DoGet(collectionURL, opts, respObject) } -func (a *APIOperations) DoNext(nextUrl string, respObject interface{}) error { - return a.DoGet(nextUrl, nil, respObject) +func (a *APIOperations) DoNext(nextURL string, respObject interface{}) error { + return a.DoGet(nextURL, nil, respObject) } func (a *APIOperations) DoModify(method string, url string, createObj interface{}, respObject interface{}) error { @@ -136,7 +136,7 @@ func (a *APIOperations) DoModify(method string, url string, createObj interface{ defer resp.Body.Close() if resp.StatusCode >= 300 { - return newApiError(resp, url) + return newAPIError(resp, url) } byteContent, err := ioutil.ReadAll(resp.Body) @@ -170,16 +170,16 @@ func (a *APIOperations) DoCreate(schemaType string, createObj interface{}, respO return errors.New("Resource type [" + schemaType + "] is not creatable") } - var collectionUrl string - collectionUrl, ok = schema.Links[COLLECTION] + var collectionURL string + collectionURL, ok = schema.Links[COLLECTION] if !ok { // return errors.New("Failed to find collection URL for [" + schemaType + "]") // This is a hack to address https://github.com/rancher/cattle/issues/254 re := regexp.MustCompile("schemas.*") - collectionUrl = re.ReplaceAllString(schema.Links[SELF], schema.PluralName) + collectionURL = re.ReplaceAllString(schema.Links[SELF], schema.PluralName) } - return a.DoModify("POST", collectionUrl, createObj, respObject) + return a.DoModify("POST", collectionURL, createObj, respObject) } func (a *APIOperations) DoUpdate(schemaType string, existing *types.Resource, updates interface{}, respObject interface{}) error { @@ -187,9 +187,9 @@ func (a *APIOperations) DoUpdate(schemaType string, existing *types.Resource, up return errors.New("Existing object is nil") } - selfUrl, ok := existing.Links[SELF] + selfURL, ok := existing.Links[SELF] if !ok { - return errors.New(fmt.Sprintf("Failed to find self URL of [%v]", existing)) + return fmt.Errorf("failed to find self URL of [%v]", existing) } if updates == nil { @@ -209,7 +209,7 @@ func (a *APIOperations) DoUpdate(schemaType string, existing *types.Resource, up return errors.New("Resource type [" + schemaType + "] is not updatable") } - return a.DoModify("PUT", selfUrl, updates, respObject) + return a.DoModify("PUT", selfURL, updates, respObject) } func (a *APIOperations) DoByID(schemaType string, id string, respObject interface{}) error { @@ -222,12 +222,12 @@ func (a *APIOperations) DoByID(schemaType string, id string, respObject interfac return errors.New("Resource type [" + schemaType + "] can not be looked up by ID") } - collectionUrl, ok := schema.Links[COLLECTION] + collectionURL, ok := schema.Links[COLLECTION] if !ok { return errors.New("Failed to find collection URL for [" + schemaType + "]") } - return a.DoGet(collectionUrl+"/"+id, nil, respObject) + return a.DoGet(collectionURL+"/"+id, nil, respObject) } func (a *APIOperations) DoResourceDelete(schemaType string, existing *types.Resource) error { @@ -240,12 +240,12 @@ func (a *APIOperations) DoResourceDelete(schemaType string, existing *types.Reso return errors.New("Resource type [" + schemaType + "] can not be deleted") } - selfUrl, ok := existing.Links[SELF] + selfURL, ok := existing.Links[SELF] if !ok { - return errors.New(fmt.Sprintf("Failed to find self URL of [%v]", existing)) + return fmt.Errorf("failed to find self URL of [%v]", existing) } - return a.DoDelete(selfUrl) + return a.DoDelete(selfURL) } func (a *APIOperations) DoAction(schemaType string, action string, @@ -255,9 +255,9 @@ func (a *APIOperations) DoAction(schemaType string, action string, return errors.New("Existing object is nil") } - actionUrl, ok := existing.Actions[action] + actionURL, ok := existing.Actions[action] if !ok { - return errors.New(fmt.Sprintf("Action [%v] not available on [%v]", action, existing)) + return fmt.Errorf("action [%v] not available on [%v]", action, existing) } _, ok = a.Types[schemaType] @@ -278,7 +278,7 @@ func (a *APIOperations) DoAction(schemaType string, action string, input = bytes.NewBuffer(bodyContent) } - req, err := http.NewRequest("POST", actionUrl, input) + req, err := http.NewRequest("POST", actionURL, input) if err != nil { return err } @@ -295,7 +295,7 @@ func (a *APIOperations) DoAction(schemaType string, action string, defer resp.Body.Close() if resp.StatusCode >= 300 { - return newApiError(resp, actionUrl) + return newAPIError(resp, actionURL) } byteContent, err := ioutil.ReadAll(resp.Body) diff --git a/vendor/github.com/rancher/norman/controller/generic_controller.go b/vendor/github.com/rancher/norman/controller/generic_controller.go index 9d41235e1..6129f445e 100644 --- a/vendor/github.com/rancher/norman/controller/generic_controller.go +++ b/vendor/github.com/rancher/norman/controller/generic_controller.go @@ -25,7 +25,7 @@ type GenericController interface { Informer() cache.SharedIndexInformer AddHandler(handler HandlerFunc) Enqueue(namespace, name string) - Start(threadiness int, ctx context.Context) error + Start(ctx context.Context, threadiness int) error } type genericController struct { @@ -69,12 +69,12 @@ func (g *genericController) AddHandler(handler HandlerFunc) { g.handlers = append(g.handlers, handler) } -func (g *genericController) Start(threadiness int, ctx context.Context) error { +func (g *genericController) Start(ctx context.Context, threadiness int) error { g.Lock() defer g.Unlock() if !g.running { - go g.run(threadiness, ctx) + go g.run(ctx, threadiness) } g.running = true @@ -88,7 +88,7 @@ func (g *genericController) queueObject(obj interface{}) { } } -func (g *genericController) run(threadiness int, ctx context.Context) { +func (g *genericController) run(ctx context.Context, threadiness int) { defer utilruntime.HandleCrash() defer g.queue.ShutDown() diff --git a/vendor/github.com/rancher/norman/types/condition.go b/vendor/github.com/rancher/norman/types/condition.go index 0d5bdd07c..aebe36e4a 100644 --- a/vendor/github.com/rancher/norman/types/condition.go +++ b/vendor/github.com/rancher/norman/types/condition.go @@ -1,108 +1,108 @@ package types -var ( - COND_EQ = QueryConditionType{"eq", 1} - COND_NE = QueryConditionType{"ne", 1} - COND_NULL = QueryConditionType{"null", 0} - COND_NOTNULL = QueryConditionType{"notnull", 0} - COND_IN = QueryConditionType{"in", -1} - COND_NOTIN = QueryConditionType{"notin", -1} - COND_OR = QueryConditionType{"or", 1} - COND_AND = QueryConditionType{"and", 1} +import ( + "github.com/rancher/norman/types/convert" +) - mods = map[string]QueryConditionType{ - COND_EQ.Name: COND_EQ, - COND_NE.Name: COND_NE, - COND_NULL.Name: COND_NULL, - COND_NOTNULL.Name: COND_NOTNULL, - COND_IN.Name: COND_IN, - COND_NOTIN.Name: COND_NOTIN, - COND_OR.Name: COND_OR, - COND_AND.Name: COND_AND, +var ( + CondEQ = QueryConditionType{ModifierEQ, 1} + CondNE = QueryConditionType{ModifierNE, 1} + CondNull = QueryConditionType{ModifierNull, 0} + CondNotNull = QueryConditionType{ModifierNotNull, 0} + CondIn = QueryConditionType{ModifierIn, -1} + CondNotIn = QueryConditionType{ModifierNotIn, -1} + CondOr = QueryConditionType{ModifierType("or"), 1} + CondAnd = QueryConditionType{ModifierType("and"), 1} + + mods = map[ModifierType]QueryConditionType{ + CondEQ.Name: CondEQ, + CondNE.Name: CondNE, + CondNull.Name: CondNull, + CondNotNull.Name: CondNotNull, + CondIn.Name: CondIn, + CondNotIn.Name: CondNotIn, + CondOr.Name: CondOr, + CondAnd.Name: CondAnd, } ) type QueryConditionType struct { - Name string + Name ModifierType Args int } type QueryCondition struct { Field string - Values []interface{} + Value string + Values map[string]bool conditionType QueryConditionType left, right *QueryCondition } +func (q *QueryCondition) Valid(data map[string]interface{}) bool { + switch q.conditionType { + case CondAnd: + if q.left == nil || q.right == nil { + return false + } + return q.left.Valid(data) && q.right.Valid(data) + case CondOr: + if q.left == nil || q.right == nil { + return false + } + return q.left.Valid(data) || q.right.Valid(data) + case CondEQ: + return q.Value == convert.ToString(data[q.Field]) + case CondNE: + return q.Value != convert.ToString(data[q.Field]) + case CondIn: + return q.Values[convert.ToString(data[q.Field])] + case CondNotIn: + return !q.Values[convert.ToString(data[q.Field])] + case CondNotNull: + return convert.ToString(data[q.Field]) != "" + case CondNull: + return convert.ToString(data[q.Field]) == "" + } + + return false +} + func (q *QueryCondition) ToCondition() Condition { cond := Condition{ Modifier: q.conditionType.Name, } - if q.conditionType.Args == 1 && len(q.Values) > 0 { - cond.Value = q.Values[0] + if q.conditionType.Args == 1 { + cond.Value = q.Value } else if q.conditionType.Args == -1 { - cond.Value = q.Values + stringValues := []string{} + for val := range q.Values { + stringValues = append(stringValues, val) + } + cond.Value = stringValues } return cond } -func ValidMod(mod string) bool { +func ValidMod(mod ModifierType) bool { _, ok := mods[mod] return ok } -func NewConditionFromString(field, mod string, values ...interface{}) *QueryCondition { - return &QueryCondition{ +func NewConditionFromString(field string, mod ModifierType, values ...string) *QueryCondition { + q := &QueryCondition{ Field: field, - Values: values, conditionType: mods[mod], + Values: map[string]bool{}, } -} -func NewCondition(mod QueryConditionType, values ...interface{}) *QueryCondition { - return &QueryCondition{ - Values: values, - conditionType: mod, + for i, value := range values { + if i == 0 { + q.Value = value + } + q.Values[value] = true } -} - -func NE(value interface{}) *QueryCondition { - return NewCondition(COND_NE, value) -} - -func EQ(value interface{}) *QueryCondition { - return NewCondition(COND_EQ, value) -} -func NULL(value interface{}) *QueryCondition { - return NewCondition(COND_NULL) -} - -func NOTNULL(value interface{}) *QueryCondition { - return NewCondition(COND_NOTNULL) -} - -func IN(values ...interface{}) *QueryCondition { - return NewCondition(COND_IN, values...) -} - -func NOTIN(values ...interface{}) *QueryCondition { - return NewCondition(COND_NOTIN, values...) -} - -func (c *QueryCondition) AND(right *QueryCondition) *QueryCondition { - return &QueryCondition{ - conditionType: COND_AND, - left: c, - right: right, - } -} - -func (c *QueryCondition) OR(right *QueryCondition) *QueryCondition { - return &QueryCondition{ - conditionType: COND_OR, - left: c, - right: right, - } + return q } diff --git a/vendor/github.com/rancher/norman/types/convert/convert.go b/vendor/github.com/rancher/norman/types/convert/convert.go index 1e585bc56..421d7aedf 100644 --- a/vendor/github.com/rancher/norman/types/convert/convert.go +++ b/vendor/github.com/rancher/norman/types/convert/convert.go @@ -132,12 +132,12 @@ func ToStringSlice(data interface{}) []string { return nil } -func ToObj(data interface{}, obj interface{}) error { +func ToObj(data interface{}, into interface{}) error { bytes, err := json.Marshal(data) if err != nil { return err } - return json.Unmarshal(bytes, obj) + return json.Unmarshal(bytes, into) } func EncodeToMap(obj interface{}) (map[string]interface{}, error) { diff --git a/vendor/github.com/rancher/norman/types/convert/ref.go b/vendor/github.com/rancher/norman/types/convert/ref.go new file mode 100644 index 000000000..b269a76cd --- /dev/null +++ b/vendor/github.com/rancher/norman/types/convert/ref.go @@ -0,0 +1,11 @@ +package convert + +import "fmt" + +func ToReference(typeName string) string { + return fmt.Sprintf("reference[%s]", typeName) +} + +func ToFullReference(path, typeName string) string { + return fmt.Sprintf("reference[%s/schemas/%s]", path, typeName) +} diff --git a/vendor/github.com/rancher/norman/types/convert/value_set_string.go b/vendor/github.com/rancher/norman/types/convert/value_set_string.go index 88f981d39..d9b329fa0 100644 --- a/vendor/github.com/rancher/norman/types/convert/value_set_string.go +++ b/vendor/github.com/rancher/norman/types/convert/value_set_string.go @@ -13,7 +13,6 @@ func ToValuesSlice(value string) []string { value = strings.TrimSpace(value) if strings.HasPrefix(value, "(") && strings.HasSuffix(value, ")") { return splitRegexp.Split(value[1:len(value)-1], -1) - } else { - return []string{value} } + return []string{value} } diff --git a/vendor/github.com/rancher/norman/types/mapper.go b/vendor/github.com/rancher/norman/types/mapper.go index 0b43e6c04..3bd858783 100644 --- a/vendor/github.com/rancher/norman/types/mapper.go +++ b/vendor/github.com/rancher/norman/types/mapper.go @@ -1,7 +1,6 @@ package types import ( - "github.com/pkg/errors" "github.com/rancher/norman/types/definition" ) @@ -11,14 +10,37 @@ type Mapper interface { ModifySchema(schema *Schema, schemas *Schemas) error } -type TypeMapper struct { +type Mappers []Mapper + +func (m Mappers) FromInternal(data map[string]interface{}) { + for _, mapper := range m { + mapper.FromInternal(data) + } +} + +func (m Mappers) ToInternal(data map[string]interface{}) { + for i := len(m) - 1; i >= 0; i-- { + m[i].ToInternal(data) + } +} + +func (m Mappers) ModifySchema(schema *Schema, schemas *Schemas) error { + for _, mapper := range m { + if err := mapper.ModifySchema(schema, schemas); err != nil { + return err + } + } + return nil +} + +type typeMapper struct { Mappers []Mapper typeName string subSchemas map[string]*Schema subArraySchemas map[string]*Schema } -func (t *TypeMapper) FromInternal(data map[string]interface{}) { +func (t *typeMapper) FromInternal(data map[string]interface{}) { for fieldName, schema := range t.subSchemas { if schema.Mapper == nil { continue @@ -38,19 +60,29 @@ func (t *TypeMapper) FromInternal(data map[string]interface{}) { } } - for _, mapper := range t.Mappers { - mapper.FromInternal(data) - } + Mappers(t.Mappers).FromInternal(data) if data != nil { - data["type"] = t.typeName + if _, ok := data["type"]; !ok { + data["type"] = t.typeName + } + name, _ := data["name"].(string) + namespace, _ := data["namespace"].(string) + + if _, ok := data["id"]; !ok { + if name != "" { + if namespace == "" { + data["id"] = name + } else { + data["id"] = namespace + ":" + name + } + } + } } } -func (t *TypeMapper) ToInternal(data map[string]interface{}) { - for i := len(t.Mappers) - 1; i >= 0; i-- { - t.Mappers[i].ToInternal(data) - } +func (t *typeMapper) ToInternal(data map[string]interface{}) { + Mappers(t.Mappers).ToInternal(data) for fieldName, schema := range t.subArraySchemas { if schema.Mapper == nil { @@ -71,7 +103,7 @@ func (t *TypeMapper) ToInternal(data map[string]interface{}) { } } -func (t *TypeMapper) ModifySchema(schema *Schema, schemas *Schemas) error { +func (t *typeMapper) ModifySchema(schema *Schema, schemas *Schemas) error { t.subSchemas = map[string]*Schema{} t.subArraySchemas = map[string]*Schema{} t.typeName = schema.ID @@ -94,11 +126,5 @@ func (t *TypeMapper) ModifySchema(schema *Schema, schemas *Schemas) error { } } - for _, mapper := range t.Mappers { - if err := mapper.ModifySchema(schema, schemas); err != nil { - return errors.Wrapf(err, "mapping type %s", schema.ID) - } - } - - return nil + return Mappers(t.Mappers).ModifySchema(schema, schemas) } diff --git a/vendor/github.com/rancher/norman/types/reflection.go b/vendor/github.com/rancher/norman/types/reflection.go index 72b47a68e..2c7bd6ee5 100644 --- a/vendor/github.com/rancher/norman/types/reflection.go +++ b/vendor/github.com/rancher/norman/types/reflection.go @@ -6,13 +6,19 @@ import ( "strconv" "strings" + "net/http" + "github.com/rancher/norman/types/convert" + "github.com/rancher/norman/types/definition" + "github.com/rancher/norman/types/slice" "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) var ( + namespacedType = reflect.TypeOf(Namespaced{}) resourceType = reflect.TypeOf(Resource{}) + typeType = reflect.TypeOf(metav1.TypeMeta{}) metaType = reflect.TypeOf(metav1.ObjectMeta{}) blacklistNames = map[string]bool{ "links": true, @@ -20,10 +26,17 @@ var ( } ) -func (s *Schemas) AddMapperForType(version *APIVersion, obj interface{}, mapper Mapper) *Schemas { +func (s *Schemas) AddMapperForType(version *APIVersion, obj interface{}, mapper ...Mapper) *Schemas { + if len(mapper) == 0 { + return s + } + t := reflect.TypeOf(obj) typeName := convert.LowerTitle(t.Name()) - return s.AddMapper(version, typeName, mapper) + if len(mapper) == 1 { + return s.AddMapper(version, typeName, mapper[0]) + } + return s.AddMapper(version, typeName, Mappers(mapper)) } func (s *Schemas) MustImport(version *APIVersion, obj interface{}, externalOverrides ...interface{}) *Schemas { @@ -35,8 +48,13 @@ func (s *Schemas) MustImport(version *APIVersion, obj interface{}, externalOverr return s } +func (s *Schemas) MustImportAndCustomize(version *APIVersion, obj interface{}, f func(*Schema), externalOverrides ...interface{}) *Schemas { + return s.MustImport(version, obj, externalOverrides...). + MustCustomizeType(version, obj, f) +} + func (s *Schemas) Import(version *APIVersion, obj interface{}, externalOverrides ...interface{}) (*Schema, error) { - types := []reflect.Type{} + var types []reflect.Type for _, override := range externalOverrides { types = append(types, reflect.TypeOf(override)) } @@ -60,6 +78,54 @@ func (s *Schemas) newSchemaFromType(version *APIVersion, t reflect.Type, typeNam return schema, nil } +func (s *Schemas) setupFilters(schema *Schema) { + if !slice.ContainsString(schema.CollectionMethods, http.MethodGet) { + return + } + for fieldName, field := range schema.ResourceFields { + var mods []ModifierType + switch field.Type { + case "enum": + mods = []ModifierType{ModifierEQ, ModifierNE, ModifierIn, ModifierNotIn} + case "string": + mods = []ModifierType{ModifierEQ, ModifierNE, ModifierIn, ModifierNotIn} + case "int": + mods = []ModifierType{ModifierEQ, ModifierNE, ModifierIn, ModifierNotIn} + case "boolean": + mods = []ModifierType{ModifierEQ, ModifierNE} + default: + if definition.IsReferenceType(field.Type) { + mods = []ModifierType{ModifierEQ, ModifierNE, ModifierIn, ModifierNotIn} + } + } + + if len(mods) > 0 { + if schema.CollectionFilters == nil { + schema.CollectionFilters = map[string]Filter{} + } + schema.CollectionFilters[fieldName] = Filter{ + Modifiers: mods, + } + } + } +} + +func (s *Schemas) MustCustomizeType(version *APIVersion, obj interface{}, f func(*Schema)) *Schemas { + name := convert.LowerTitle(reflect.TypeOf(obj).Name()) + schema := s.Schema(version, name) + if schema == nil { + panic("Failed to find schema " + name) + } + + f(schema) + + if schema.SubContext != "" { + s.schemasBySubContext[schema.SubContext] = schema + } + + return s +} + func (s *Schemas) importType(version *APIVersion, t reflect.Type, overrides ...reflect.Type) (*Schema, error) { typeName := convert.LowerTitle(t.Name()) @@ -75,8 +141,13 @@ func (s *Schemas) importType(version *APIVersion, t reflect.Type, overrides ...r return nil, err } - mapper := s.mapper(&schema.Version, schema.ID) - if mapper != nil { + mappers := s.mapper(&schema.Version, schema.ID) + if schema.CanList() { + mappers = append(s.DefaultMappers, mappers...) + } + mappers = append(mappers, s.DefaultPostMappers...) + + if len(mappers) > 0 { copy, err := s.newSchemaFromType(version, t, typeName) if err != nil { return nil, err @@ -90,14 +161,16 @@ func (s *Schemas) importType(version *APIVersion, t reflect.Type, overrides ...r } } - if mapper == nil { - mapper = &TypeMapper{} + mapper := &typeMapper{ + Mappers: mappers, } if err := mapper.ModifySchema(schema, s); err != nil { return nil, err } + s.setupFilters(schema) + schema.Mapper = mapper s.AddSchema(schema) @@ -114,6 +187,9 @@ func (s *Schemas) readFields(schema *Schema, t reflect.Type) error { schema.ResourceMethods = []string{"GET", "PUT", "DELETE"} } + hasType := false + hasMeta := false + for i := 0; i < t.NumField(); i++ { field := t.Field(i) @@ -128,12 +204,23 @@ func (s *Schemas) readFields(schema *Schema, t reflect.Type) error { continue } + if field.Anonymous && jsonName == "" && field.Type == typeType { + hasType = true + } + + if field.Anonymous && jsonName == "metadata" && field.Type == metaType { + hasMeta = true + } + if field.Anonymous && jsonName == "" { t := field.Type if t.Kind() == reflect.Ptr { t = t.Elem() } if t.Kind() == reflect.Struct { + if t == namespacedType { + schema.Scope = NamespaceScope + } if err := s.readFields(schema, t); err != nil { return err } @@ -144,6 +231,9 @@ func (s *Schemas) readFields(schema *Schema, t reflect.Type) error { fieldName := jsonName if fieldName == "" { fieldName = convert.LowerTitle(field.Name) + if strings.HasSuffix(fieldName, "ID") { + fieldName = strings.TrimSuffix(fieldName, "ID") + "Id" + } } if blacklistNames[fieldName] { @@ -156,6 +246,7 @@ func (s *Schemas) readFields(schema *Schema, t reflect.Type) error { schemaField := Field{ Create: true, Update: true, + Nullable: true, CodeName: field.Name, } @@ -177,15 +268,15 @@ func (s *Schemas) readFields(schema *Schema, t reflect.Type) error { schemaField.Type = inferedType } - if field.Type == metaType { - schema.CollectionMethods = []string{"GET", "POST"} - schema.ResourceMethods = []string{"GET", "PUT", "DELETE"} - } - logrus.Debugf("Setting field %s.%s: %#v", schema.ID, fieldName, schemaField) schema.ResourceFields[fieldName] = schemaField } + if hasType && hasMeta { + schema.CollectionMethods = []string{"GET", "POST"} + schema.ResourceMethods = []string{"GET", "PUT", "DELETE"} + } + return nil } diff --git a/vendor/github.com/rancher/norman/types/schema_funcs.go b/vendor/github.com/rancher/norman/types/schema_funcs.go new file mode 100644 index 000000000..df6f6ff6d --- /dev/null +++ b/vendor/github.com/rancher/norman/types/schema_funcs.go @@ -0,0 +1,26 @@ +package types + +import ( + "net/http" + + "github.com/rancher/norman/types/slice" +) + +func (s *Schema) MustCustomizeField(name string, f func(f Field) Field) *Schema { + field, ok := s.ResourceFields[name] + if !ok { + panic("Failed to find field " + name + " on schema " + s.ID) + } + s.ResourceFields[name] = f(field) + return s +} + +func (v *APIVersion) Equals(other *APIVersion) bool { + return v.Version == other.Version && + v.Group == other.Group && + v.Path == other.Path +} + +func (s *Schema) CanList() bool { + return slice.ContainsString(s.CollectionMethods, http.MethodGet) +} diff --git a/vendor/github.com/rancher/norman/types/schemas.go b/vendor/github.com/rancher/norman/types/schemas.go index f7a690543..047021ee9 100644 --- a/vendor/github.com/rancher/norman/types/schemas.go +++ b/vendor/github.com/rancher/norman/types/schemas.go @@ -13,25 +13,43 @@ type SchemaCollection struct { Data []Schema } +type SchemaInitFunc func(*Schemas) *Schemas + type Schemas struct { - schemasByPath map[string]map[string]*Schema - mappers map[string]map[string]Mapper - versions []APIVersion - schemas []*Schema - errors []error + schemasByPath map[string]map[string]*Schema + schemasBySubContext map[string]*Schema + mappers map[string]map[string][]Mapper + DefaultMappers []Mapper + DefaultPostMappers []Mapper + versions []APIVersion + schemas []*Schema + errors []error } func NewSchemas() *Schemas { return &Schemas{ - schemasByPath: map[string]map[string]*Schema{}, - mappers: map[string]map[string]Mapper{}, + schemasByPath: map[string]map[string]*Schema{}, + schemasBySubContext: map[string]*Schema{}, + mappers: map[string]map[string][]Mapper{}, } } +func (s *Schemas) Init(initFunc SchemaInitFunc) *Schemas { + return initFunc(s) +} + func (s *Schemas) Err() error { return NewErrors(s.errors) } +func (s *Schemas) SubContext(subContext string) *Schema { + return s.schemasBySubContext[subContext] +} + +func (s *Schemas) SubContextSchemas() map[string]*Schema { + return s.schemasBySubContext +} + func (s *Schemas) AddSchemas(schema *Schemas) *Schemas { for _, schema := range schema.Schemas() { s.AddSchema(schema) @@ -40,7 +58,7 @@ func (s *Schemas) AddSchemas(schema *Schemas) *Schemas { } func (s *Schemas) AddSchema(schema *Schema) *Schemas { - schema.Type = "schema" + schema.Type = "/v1-meta/schemas/schema" if schema.ID == "" { s.errors = append(s.errors, fmt.Errorf("ID is not set on schema: %v", schema)) return s @@ -58,6 +76,9 @@ func (s *Schemas) AddSchema(schema *Schema) *Schemas { if schema.CodeNamePlural == "" { schema.CodeNamePlural = name.GuessPluralName(schema.CodeName) } + if schema.BaseType == "" { + schema.BaseType = schema.ID + } schemas, ok := s.schemasByPath[schema.Version.Path] if !ok { @@ -71,20 +92,21 @@ func (s *Schemas) AddSchema(schema *Schema) *Schemas { s.schemas = append(s.schemas, schema) } + if schema.SubContext != "" { + s.schemasBySubContext[schema.SubContext] = schema + } + return s } func (s *Schemas) AddMapper(version *APIVersion, schemaID string, mapper Mapper) *Schemas { mappers, ok := s.mappers[version.Path] if !ok { - mappers = map[string]Mapper{} + mappers = map[string][]Mapper{} s.mappers[version.Path] = mappers } - if _, ok := mappers[schemaID]; !ok { - mappers[schemaID] = mapper - } - + mappers[schemaID] = append(mappers[schemaID], mapper) return s } @@ -100,7 +122,7 @@ func (s *Schemas) Schemas() []*Schema { return s.schemas } -func (s *Schemas) mapper(version *APIVersion, name string) Mapper { +func (s *Schemas) mapper(version *APIVersion, name string) []Mapper { var ( path string ) @@ -133,10 +155,10 @@ func (s *Schemas) Schema(version *APIVersion, name string) *Schema { path string ) - if strings.Contains(name, "/") { - idx := strings.LastIndex(name, "/") - path = name[0:idx] - name = name[idx+1:] + if strings.Contains(name, "/schemas/") { + parts := strings.SplitN(name, "/schemas/", 2) + path = parts[0] + name = parts[1] } else if version != nil { path = version.Path } else { diff --git a/vendor/github.com/rancher/norman/types/server_types.go b/vendor/github.com/rancher/norman/types/server_types.go index c719d965f..fd452f82a 100644 --- a/vendor/github.com/rancher/norman/types/server_types.go +++ b/vendor/github.com/rancher/norman/types/server_types.go @@ -27,12 +27,14 @@ func (r *RawResource) MarshalJSON() ([]byte, error) { if r.ID != "" { data["id"] = r.ID } + data["type"] = r.Type + data["baseType"] = r.Schema.BaseType data["links"] = r.Links if r.ActionLinks { data["actionLinks"] = r.Actions } else { - data["action"] = r.Actions + data["actions"] = r.Actions } return json.Marshal(data) } @@ -41,12 +43,19 @@ type ActionHandler func(actionName string, action *Action, request *APIContext) type RequestHandler func(request *APIContext) error +type QueryFilter func(opts QueryOptions, data []map[string]interface{}) []map[string]interface{} + type Validator func(request *APIContext, data map[string]interface{}) error type Formatter func(request *APIContext, resource *RawResource) type ErrorHandler func(request *APIContext, err error) +type SubContextAttributeProvider interface { + Query(apiContext *APIContext, schema *Schema) []*QueryCondition + Create(apiContext *APIContext, schema *Schema) map[string]interface{} +} + type ResponseWriter interface { Write(apiContext *APIContext, code int, obj interface{}) } @@ -57,22 +66,24 @@ type AccessControl interface { } type APIContext struct { - Action string - ID string - Type string - Link string - Method string - Schema *Schema - Schemas *Schemas - Version *APIVersion - ResponseFormat string - ReferenceValidator ReferenceValidator - ResponseWriter ResponseWriter - QueryOptions *QueryOptions - Body map[string]interface{} - URLBuilder URLBuilder - AccessControl AccessControl - SubContext map[string]interface{} + Action string + ID string + Type string + Link string + Method string + Schema *Schema + Schemas *Schemas + Version *APIVersion + ResponseFormat string + ReferenceValidator ReferenceValidator + ResponseWriter ResponseWriter + QueryFilter QueryFilter + SubContextAttributeProvider SubContextAttributeProvider + //QueryOptions *QueryOptions + URLBuilder URLBuilder + AccessControl AccessControl + SubContext map[string]string + Attributes map[string]interface{} Request *http.Request Response http.ResponseWriter @@ -82,6 +93,30 @@ func (r *APIContext) WriteResponse(code int, obj interface{}) { r.ResponseWriter.Write(r, code, obj) } +func (r *APIContext) FilterList(opts QueryOptions, obj []map[string]interface{}) []map[string]interface{} { + return r.QueryFilter(opts, obj) +} + +func (r *APIContext) FilterObject(opts QueryOptions, obj map[string]interface{}) map[string]interface{} { + opts.Pagination = nil + result := r.QueryFilter(opts, []map[string]interface{}{obj}) + if len(result) == 0 { + return nil + } + return result[0] +} + +func (r *APIContext) Filter(opts QueryOptions, obj interface{}) interface{} { + switch v := obj.(type) { + case []map[string]interface{}: + return r.FilterList(opts, v) + case map[string]interface{}: + return r.FilterObject(opts, v) + } + + return nil +} + var ( ASC = SortOrder("asc") DESC = SortOrder("desc") @@ -100,20 +135,21 @@ type ReferenceValidator interface { type URLBuilder interface { Current() string - Collection(schema *Schema) string + Collection(schema *Schema, versionOverride *APIVersion) string + SubContextCollection(subContext *Schema, contextName string, schema *Schema) string + SchemaLink(schema *Schema) string ResourceLink(resource *RawResource) string RelativeToRoot(path string) string - //Link(resource Resource, name string) string - //ReferenceLink(resource Resource) string - //ReferenceByIdLink(resourceType string, id string) string - Version(version string) string + Version(version APIVersion) string + Marker(marker string) string ReverseSort(order SortOrder) string + Sort(field string) string SetSubContext(subContext string) } type Store interface { ByID(apiContext *APIContext, schema *Schema, id string) (map[string]interface{}, error) - List(apiContext *APIContext, schema *Schema, opt *QueryOptions) ([]map[string]interface{}, error) + List(apiContext *APIContext, schema *Schema, opt QueryOptions) ([]map[string]interface{}, error) Create(apiContext *APIContext, schema *Schema, data map[string]interface{}) (map[string]interface{}, error) Update(apiContext *APIContext, schema *Schema, data map[string]interface{}, id string) (map[string]interface{}, error) Delete(apiContext *APIContext, schema *Schema, id string) error diff --git a/vendor/github.com/rancher/norman/types/slice/contains.go b/vendor/github.com/rancher/norman/types/slice/contains.go new file mode 100644 index 000000000..170f11d11 --- /dev/null +++ b/vendor/github.com/rancher/norman/types/slice/contains.go @@ -0,0 +1,10 @@ +package slice + +func ContainsString(slice []string, item string) bool { + for _, j := range slice { + if j == item { + return true + } + } + return false +} diff --git a/vendor/github.com/rancher/norman/types/types.go b/vendor/github.com/rancher/norman/types/types.go index 36eddca1e..b465f86ab 100644 --- a/vendor/github.com/rancher/norman/types/types.go +++ b/vendor/github.com/rancher/norman/types/types.go @@ -27,12 +27,23 @@ type Sort struct { Name string `json:"name,omitempty"` Order SortOrder `json:"order,omitempty"` Reverse string `json:"reverse,omitempty"` - Links map[string]string `json:"sortLinks,omitempty"` + Links map[string]string `json:"links,omitempty"` } +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 string `json:"modifier,omitempty"` - Value interface{} `json:"value,omitempty"` + Modifier ModifierType `json:"modifier,omitempty"` + Value interface{} `json:"value,omitempty"` } type Pagination struct { @@ -40,6 +51,7 @@ type Pagination struct { First string `json:"first,omitempty"` Previous string `json:"previous,omitempty"` Next string `json:"next,omitempty"` + Last string `json:"last,omitempty"` Limit *int64 `json:"limit,omitempty"` Total *int64 `json:"total,omitempty"` Partial bool `json:"partial,omitempty"` @@ -59,12 +71,20 @@ type APIVersion struct { SubContexts map[string]bool `json:"subContext,omitempty"` } +type Namespaced struct{} + +var NamespaceScope TypeScope = "namespace" + +type TypeScope string + type Schema struct { ID string `json:"id,omitempty"` CodeName string `json:"-"` CodeNamePlural string `json:"-"` PkgName string `json:"-"` Type string `json:"type,omitempty"` + BaseType string `json:"baseType,omitempty"` + SubContext string `json:"-,omitempty"` Links map[string]string `json:"links"` Version APIVersion `json:"version"` PluralName string `json:"pluralName,omitempty"` @@ -75,6 +95,7 @@ type Schema struct { CollectionFields map[string]Field `json:"collectionFields,omitempty"` CollectionActions map[string]Action `json:"collectionActions,omitempty"` CollectionFilters map[string]Filter `json:"collectionFilters,omitempty"` + Scope TypeScope `json:"-"` InternalSchema *Schema `json:"-"` Mapper Mapper `json:"-"` @@ -115,7 +136,7 @@ type Action struct { } type Filter struct { - Modifiers []string `json:"modifiers,omitempty"` + Modifiers []ModifierType `json:"modifiers,omitempty"` } type ListOpts struct { diff --git a/vendor/github.com/rancher/types/apis/cluster.cattle.io/v1/types.go b/vendor/github.com/rancher/types/apis/cluster.cattle.io/v1/types.go index 6eb37c5cd..2fceff2db 100644 --- a/vendor/github.com/rancher/types/apis/cluster.cattle.io/v1/types.go +++ b/vendor/github.com/rancher/types/apis/cluster.cattle.io/v1/types.go @@ -107,7 +107,7 @@ type AzureKubernetesServiceConfig struct { type RancherKubernetesEngineConfig struct { // Kubernetes nodes - Hosts []RKEConfigHost `yaml:"hosts" json:"hosts,omitempty"` + Nodes []RKEConfigNode `yaml:"nodes" json:"nodes,omitempty"` // Kubernetes components Services RKEConfigServices `yaml:"services" json:"services,omitempty"` // Network configuration used in the kubernetes cluster (flannel, calico) @@ -120,18 +120,18 @@ type RancherKubernetesEngineConfig struct { SSHKeyPath string `yaml:"ssh_key_path" json:"sshKeyPath,omitempty"` } -type RKEConfigHost struct { - // SSH IP address of the host - IP string `yaml:"ip" json:"ip,omitempty"` - // Advertised address that will be used for components communication - AdvertiseAddress string `yaml:"advertise_address" json:"advertiseAddress,omitempty"` - // Host role in kubernetes cluster (controlplane, worker, or etcd) +type RKEConfigNode struct { + // IP or FQDN that is fully resolvable and used for SSH communication + Address string `yaml:"address" json:"address,omitempty"` + // Optional - Internal address that will be used for components communication + InternalAddress string `yaml:"internal_address" json:"internalAddress,omitempty"` + // Node role in kubernetes cluster (controlplane, worker, or etcd) Role []string `yaml:"role" json:"role,omitempty"` - // Hostname of the host - AdvertisedHostname string `yaml:"advertised_hostname" json:"advertisedHostname,omitempty"` + // Optional - Hostname of the node + HostnameOverride string `yaml:"hostname_override" json:"hostnameOverride,omitempty"` // SSH usesr that will be used by RKE User string `yaml:"user" json:"user,omitempty"` - // Docker socket on the host that will be used in tunneling + // Optional - Docker socket on the node that will be used in tunneling DockerSocket string `yaml:"docker_socket" json:"dockerSocket,omitempty"` } diff --git a/vendor/github.com/rancher/types/apis/cluster.cattle.io/v1/zz_generated_cluster_controller.go b/vendor/github.com/rancher/types/apis/cluster.cattle.io/v1/zz_generated_cluster_controller.go index 25bdc58f1..c8579f868 100644 --- a/vendor/github.com/rancher/types/apis/cluster.cattle.io/v1/zz_generated_cluster_controller.go +++ b/vendor/github.com/rancher/types/apis/cluster.cattle.io/v1/zz_generated_cluster_controller.go @@ -38,7 +38,7 @@ type ClusterController interface { Informer() cache.SharedIndexInformer AddHandler(handler ClusterHandlerFunc) Enqueue(namespace, name string) - Start(threadiness int, ctx context.Context) error + Start(ctx context.Context, threadiness int) error } type ClusterInterface interface { diff --git a/vendor/github.com/rancher/types/apis/cluster.cattle.io/v1/zz_generated_cluster_node_controller.go b/vendor/github.com/rancher/types/apis/cluster.cattle.io/v1/zz_generated_cluster_node_controller.go index e2c450345..d51a26854 100644 --- a/vendor/github.com/rancher/types/apis/cluster.cattle.io/v1/zz_generated_cluster_node_controller.go +++ b/vendor/github.com/rancher/types/apis/cluster.cattle.io/v1/zz_generated_cluster_node_controller.go @@ -38,7 +38,7 @@ type ClusterNodeController interface { Informer() cache.SharedIndexInformer AddHandler(handler ClusterNodeHandlerFunc) Enqueue(namespace, name string) - Start(threadiness int, ctx context.Context) error + Start(ctx context.Context, threadiness int) error } type ClusterNodeInterface interface { diff --git a/vendor/github.com/rancher/types/apis/cluster.cattle.io/v1/zz_generated_deepcopy.go b/vendor/github.com/rancher/types/apis/cluster.cattle.io/v1/zz_generated_deepcopy.go index 78419ae54..e7dc29ef2 100644 --- a/vendor/github.com/rancher/types/apis/cluster.cattle.io/v1/zz_generated_deepcopy.go +++ b/vendor/github.com/rancher/types/apis/cluster.cattle.io/v1/zz_generated_deepcopy.go @@ -445,7 +445,7 @@ func (in *NetworkConfig) DeepCopy() *NetworkConfig { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RKEConfigHost) DeepCopyInto(out *RKEConfigHost) { +func (in *RKEConfigNode) DeepCopyInto(out *RKEConfigNode) { *out = *in if in.Role != nil { in, out := &in.Role, &out.Role @@ -455,12 +455,12 @@ func (in *RKEConfigHost) DeepCopyInto(out *RKEConfigHost) { return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RKEConfigHost. -func (in *RKEConfigHost) DeepCopy() *RKEConfigHost { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RKEConfigNode. +func (in *RKEConfigNode) DeepCopy() *RKEConfigNode { if in == nil { return nil } - out := new(RKEConfigHost) + out := new(RKEConfigNode) in.DeepCopyInto(out) return out } @@ -490,9 +490,9 @@ func (in *RKEConfigServices) DeepCopy() *RKEConfigServices { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RancherKubernetesEngineConfig) DeepCopyInto(out *RancherKubernetesEngineConfig) { *out = *in - if in.Hosts != nil { - in, out := &in.Hosts, &out.Hosts - *out = make([]RKEConfigHost, len(*in)) + if in.Nodes != nil { + in, out := &in.Nodes, &out.Nodes + *out = make([]RKEConfigNode, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } diff --git a/vendor/github.com/rancher/types/vendor.conf b/vendor/github.com/rancher/types/vendor.conf index 15ea699fa..e59a4b2e8 100644 --- a/vendor/github.com/rancher/types/vendor.conf +++ b/vendor/github.com/rancher/types/vendor.conf @@ -3,4 +3,4 @@ github.com/rancher/types k8s.io/kubernetes v1.8.3 transitive=true,staging=true bitbucket.org/ww/goautoneg a547fc61f48d567d5b4ec6f8aee5573d8efce11d https://github.com/rancher/goautoneg.git -github.com/rancher/norman 80024df69414f7cce0847ea72b0557f14edbc852 +github.com/rancher/norman faa1fb2148211044253fc2f6403008958c72b1f0 From 41c48877baf869e9696daf55908cd9a195f7a526 Mon Sep 17 00:00:00 2001 From: galal-hussein Date: Tue, 28 Nov 2017 19:45:24 +0200 Subject: [PATCH 2/2] Structure and config changes --- cluster.yml | 16 ++++---- cluster/addons.go | 2 +- cluster/cluster.go | 83 +++++++++++++++++++++++++------------- cluster/hosts.go | 8 ++-- cluster/network.go | 9 +++-- cluster/validation.go | 72 ++++++++++++++++++++++++++++++--- cmd/config.go | 55 +++++++++++++++---------- cmd/up.go | 2 +- hosts/dialer.go | 10 ++--- hosts/hosts.go | 32 ++++++++------- main.go | 2 +- pki/deploy.go | 12 +++--- pki/pki.go | 24 ++++++++--- pki/pki_test.go | 14 +++---- services/etcd.go | 14 +++---- services/kubeapi.go | 7 ++-- services/kubecontroller.go | 4 +- services/kubelet.go | 6 +-- services/kubeproxy.go | 4 +- services/proxy.go | 8 ++-- services/scheduler.go | 4 +- vendor.conf | 4 +- 22 files changed, 256 insertions(+), 136 deletions(-) diff --git a/cluster.yml b/cluster.yml index b1939b5b4..568b97f37 100644 --- a/cluster.yml +++ b/cluster.yml @@ -14,18 +14,18 @@ network: options: foo: bar -hosts: - - advertised_hostname: server1 - ip: 1.1.1.1 +nodes: + - address: 1.1.1.1 user: ubuntu role: [controlplane, etcd] - docker_socket: /var/run/docker.sock - advertise_address: 10.1.1.1 - - advertised_hostname: server2 - ip: 2.2.2.2 + - address: 2.2.2.2 user: ubuntu role: [worker] - advertise_address: 10.2.2.2 + - address: example.com + user: ubuntu + role: [worker] + hostname_override: node3 + internal_address: 192.168.1.6 services: etcd: diff --git a/cluster/addons.go b/cluster/addons.go index 5691bc2d0..f19f30f3f 100644 --- a/cluster/addons.go +++ b/cluster/addons.go @@ -56,7 +56,7 @@ func (c *Cluster) doAddonDeploy(addonYaml, resourceName string) error { logrus.Infof("[addons] Executing deploy job..") - addonJob := addons.GetAddonsExcuteJob(resourceName, c.ControlPlaneHosts[0].AdvertisedHostname, c.Services.KubeAPI.Image) + addonJob := addons.GetAddonsExcuteJob(resourceName, c.ControlPlaneHosts[0].HostnameOverride, c.Services.KubeAPI.Image) err = c.ApplySystemAddonExcuteJob(addonJob) if err != nil { return fmt.Errorf("Failed to deploy addon execute job: %v", err) diff --git a/cluster/cluster.go b/cluster/cluster.go index 58d9cda11..76f5e320b 100644 --- a/cluster/cluster.go +++ b/cluster/cluster.go @@ -33,12 +33,19 @@ type Cluster struct { } const ( - X509AuthenticationProvider = "x509" - DefaultClusterConfig = "cluster.yml" - StateConfigMapName = "cluster-state" - UpdateStateTimeout = 30 - GetStateTimeout = 30 - KubernetesClientTimeOut = 30 + X509AuthenticationProvider = "x509" + DefaultClusterConfig = "cluster.yml" + DefaultServiceClusterIPRange = "10.233.0.0/18" + DefaultClusterCIDR = "10.233.64.0/18" + DefaultClusterDNSService = "10.233.0.3" + DefaultClusterDomain = "cluster.local" + DefaultInfraContainerImage = "gcr.io/google_containers/pause-amd64:3.0" + DefaultAuthStrategy = "x509" + DefaultNetworkPlugin = "flannel" + StateConfigMapName = "cluster-state" + UpdateStateTimeout = 30 + GetStateTimeout = 30 + KubernetesClientTimeOut = 30 ) func (c *Cluster) DeployClusterPlanes() error { @@ -96,26 +103,46 @@ func parseClusterFile(clusterFile string) (*Cluster, error) { if err != nil { return nil, err } - for i, host := range kubeCluster.Hosts { - if len(host.AdvertisedHostname) == 0 { - return nil, fmt.Errorf("Hostname for host (%d) is not provided", i+1) - } else if len(host.User) == 0 { - return nil, fmt.Errorf("User for host (%d) is not provided", i+1) - } else if len(host.Role) == 0 { - return nil, fmt.Errorf("Role for host (%d) is not provided", i+1) - - } else if host.AdvertiseAddress == "" { - // if control_plane_ip is not set, - // default to the main IP - kubeCluster.Hosts[i].AdvertiseAddress = host.IP + // Setting cluster Defaults + kubeCluster.setClusterDefaults() + + return &kubeCluster, nil +} + +func (c *Cluster) setClusterDefaults() { + for i, host := range c.Nodes { + if len(host.InternalAddress) == 0 { + c.Nodes[i].InternalAddress = c.Nodes[i].Address } - for _, role := range host.Role { - if role != services.ETCDRole && role != services.ControlRole && role != services.WorkerRole { - return nil, fmt.Errorf("Role [%s] for host (%d) is not recognized", role, i+1) - } + if len(host.HostnameOverride) == 0 { + // This is a temporary modification + c.Nodes[i].HostnameOverride = c.Nodes[i].Address } } - return &kubeCluster, nil + if len(c.Services.KubeAPI.ServiceClusterIPRange) == 0 { + c.Services.KubeAPI.ServiceClusterIPRange = DefaultServiceClusterIPRange + } + if len(c.Services.KubeController.ServiceClusterIPRange) == 0 { + c.Services.KubeController.ServiceClusterIPRange = DefaultServiceClusterIPRange + } + if len(c.Services.KubeController.ClusterCIDR) == 0 { + c.Services.KubeController.ClusterCIDR = DefaultClusterCIDR + } + if len(c.Services.Kubelet.ClusterDNSServer) == 0 { + c.Services.Kubelet.ClusterDNSServer = DefaultClusterDNSService + } + if len(c.Services.Kubelet.ClusterDomain) == 0 { + c.Services.Kubelet.ClusterDomain = DefaultClusterDomain + } + if len(c.Services.Kubelet.InfraContainerImage) == 0 { + c.Services.Kubelet.InfraContainerImage = DefaultInfraContainerImage + } + if len(c.Authentication.Strategy) == 0 { + c.Authentication.Strategy = DefaultAuthStrategy + } + if len(c.Network.Plugin) == 0 { + c.Network.Plugin = DefaultNetworkPlugin + } } func GetLocalKubeConfig(configPath string) string { @@ -144,11 +171,11 @@ func ReconcileCluster(kubeCluster, currentCluster *Cluster) error { cpToDelete := hosts.GetToDeleteHosts(currentCluster.ControlPlaneHosts, kubeCluster.ControlPlaneHosts) for _, toDeleteHost := range cpToDelete { if err := hosts.DeleteNode(&toDeleteHost, kubeClient); err != nil { - return fmt.Errorf("Failed to delete controlplane node %s from cluster", toDeleteHost.AdvertisedHostname) + return fmt.Errorf("Failed to delete controlplane node %s from cluster", toDeleteHost.Address) } // attempting to clean up the host if err := reconcileHostCleaner(toDeleteHost, key, false); err != nil { - logrus.Warnf("[reconcile] Couldn't clean up controlplane node [%s]: %v", toDeleteHost.AdvertisedHostname, err) + logrus.Warnf("[reconcile] Couldn't clean up controlplane node [%s]: %v", toDeleteHost.Address, err) continue } } @@ -157,11 +184,11 @@ func ReconcileCluster(kubeCluster, currentCluster *Cluster) error { wpToDelete := hosts.GetToDeleteHosts(currentCluster.WorkerHosts, kubeCluster.WorkerHosts) for _, toDeleteHost := range wpToDelete { if err := hosts.DeleteNode(&toDeleteHost, kubeClient); err != nil { - return fmt.Errorf("Failed to delete worker node %s from cluster", toDeleteHost.AdvertisedHostname) + return fmt.Errorf("Failed to delete worker node %s from cluster", toDeleteHost.Address) } // attempting to clean up the host if err := reconcileHostCleaner(toDeleteHost, key, true); err != nil { - logrus.Warnf("[reconcile] Couldn't clean up worker node [%s]: %v", toDeleteHost.AdvertisedHostname, err) + logrus.Warnf("[reconcile] Couldn't clean up worker node [%s]: %v", toDeleteHost.Address, err) continue } } @@ -201,7 +228,7 @@ func rebuildLocalAdminConfig(kubeCluster *Cluster) error { currentKubeConfig := kubeCluster.Certificates[pki.KubeAdminCommonName] caCrt := kubeCluster.Certificates[pki.CACertName].Certificate newConfig := pki.GetKubeConfigX509WithData( - "https://"+kubeCluster.ControlPlaneHosts[0].IP+":6443", + "https://"+kubeCluster.ControlPlaneHosts[0].Address+":6443", pki.KubeAdminCommonName, string(cert.EncodeCertPEM(caCrt)), string(cert.EncodeCertPEM(currentKubeConfig.Certificate)), diff --git a/cluster/hosts.go b/cluster/hosts.go index 8147da434..d02539987 100644 --- a/cluster/hosts.go +++ b/cluster/hosts.go @@ -48,11 +48,11 @@ func (c *Cluster) InvertIndexHosts() error { c.EtcdHosts = make([]hosts.Host, 0) c.WorkerHosts = make([]hosts.Host, 0) c.ControlPlaneHosts = make([]hosts.Host, 0) - for _, host := range c.Hosts { + for _, host := range c.Nodes { for _, role := range host.Role { - logrus.Debugf("Host: " + host.AdvertisedHostname + " has role: " + role) + logrus.Debugf("Host: " + host.Address + " has role: " + role) newHost := hosts.Host{ - RKEConfigHost: host, + RKEConfigNode: host, } switch role { case services.ETCDRole: @@ -62,7 +62,7 @@ func (c *Cluster) InvertIndexHosts() error { case services.WorkerRole: c.WorkerHosts = append(c.WorkerHosts, newHost) default: - return fmt.Errorf("Failed to recognize host [%s] role %s", host.AdvertisedHostname, role) + return fmt.Errorf("Failed to recognize host [%s] role %s", host.Address, role) } } } diff --git a/cluster/network.go b/cluster/network.go index 802528013..9fd8cb570 100644 --- a/cluster/network.go +++ b/cluster/network.go @@ -11,16 +11,19 @@ import ( const ( NetworkPluginResourceName = "rke-netwok-plugin" + FlannelNetworkPlugin = "flannel" + CalicoNetworkPlugin = "calico" + CanalNetworkPlugin = "canal" ) func (c *Cluster) DeployNetworkPlugin() error { logrus.Infof("[network] Setting up network plugin: %s", c.Network.Plugin) switch c.Network.Plugin { - case "flannel": + case FlannelNetworkPlugin: return c.doFlannelDeploy() - case "calico": + case CalicoNetworkPlugin: return c.doCalicoDeploy() - case "canal": + case CanalNetworkPlugin: return c.doCanalDeploy() default: return fmt.Errorf("[network] Unsupported network plugin: %s", c.Network.Plugin) diff --git a/cluster/validation.go b/cluster/validation.go index b49f511c4..a0b7e248c 100644 --- a/cluster/validation.go +++ b/cluster/validation.go @@ -3,6 +3,8 @@ package cluster import ( "fmt" "strings" + + "github.com/rancher/rke/services" ) func (c *Cluster) ValidateCluster() error { @@ -10,19 +12,79 @@ func (c *Cluster) ValidateCluster() error { if len(c.ControlPlaneHosts) == 0 { return fmt.Errorf("Cluster must have at least one control plane host") } - if len(c.EtcdHosts) == 0 { - return fmt.Errorf("Cluster must have at least one etcd host") + if len(c.EtcdHosts)%2 == 0 { + return fmt.Errorf("Cluster must have odd number of etcd nodes") + } + if len(c.WorkerHosts) == 0 { + return fmt.Errorf("Cluster must have at least one worker plane host") + } + + // validate hosts options + if err := validateHostsOptions(c); err != nil { + return err + } + + // validate Auth options + if err := validateAuthOptions(c); err != nil { + return err + } + + // validate Network options + if err := validateNetworkOptions(c); err != nil { + return err } // validate services options - err := validateServicesOption(c) - if err != nil { + if err := validateServicesOptions(c); err != nil { return err } return nil } -func validateServicesOption(c *Cluster) error { +func validateAuthOptions(c *Cluster) error { + if c.Authentication.Strategy != DefaultAuthStrategy { + return fmt.Errorf("Authentication strategy [%s] is not supported", c.Authentication.Strategy) + } + return nil +} + +func validateNetworkOptions(c *Cluster) error { + if c.Network.Plugin != FlannelNetworkPlugin && c.Network.Plugin != CalicoNetworkPlugin && c.Network.Plugin != CanalNetworkPlugin { + return fmt.Errorf("Network plugin [%s] is not supported", c.Network.Plugin) + } + return nil +} + +func validateHostsOptions(c *Cluster) error { + for i, host := range c.Nodes { + if len(host.Address) == 0 { + return fmt.Errorf("User for host (%d) is not provided", i+1) + } + if len(host.User) == 0 { + return fmt.Errorf("User for host (%d) is not provided", i+1) + } + if len(host.Role) == 0 { + return fmt.Errorf("Role for host (%d) is not provided", i+1) + } + for _, role := range host.Role { + if role != services.ETCDRole && role != services.ControlRole && role != services.WorkerRole { + return fmt.Errorf("Role [%s] for host (%d) is not recognized", role, i+1) + } + } + k := 0 + for _, role := range host.Role { + if role == services.ControlRole || role == services.WorkerRole { + k++ + } + } + if k > 1 { + return fmt.Errorf("Host (%d) can't contain both worker and controlplane roles", i+1) + } + } + return nil +} + +func validateServicesOptions(c *Cluster) error { servicesOptions := map[string]string{ "etcd_image": c.Services.Etcd.Image, "kube_api_image": c.Services.KubeAPI.Image, diff --git a/cmd/config.go b/cmd/config.go index 7320945e4..26134b004 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -42,7 +42,11 @@ func ConfigCommand() cli.Command { func getConfig(reader *bufio.Reader, text, def string) (string, error) { for { - fmt.Printf("%s [%s]: ", text, def) + if def == "" { + fmt.Printf("%s [%s]: ", text, "none") + } else { + fmt.Printf("%s [%s]: ", text, def) + } input, err := reader.ReadString('\n') if err != nil { return "", err @@ -81,10 +85,17 @@ func clusterConfig(ctx *cli.Context) error { // Generate empty configuration file if ctx.Bool("empty") { - cluster.Hosts = make([]v1.RKEConfigHost, 1) + cluster.Nodes = make([]v1.RKEConfigNode, 1) return writeConfig(&cluster, configFile, print) } + // Get number of hosts + sshKeyPath, err := getConfig(reader, "SSH Private Key Path", "~/.ssh/id_rsa") + if err != nil { + return err + } + cluster.SSHKeyPath = sshKeyPath + // Get number of hosts numberOfHostsString, err := getConfig(reader, "Number of Hosts", "3") if err != nil { @@ -96,13 +107,13 @@ func clusterConfig(ctx *cli.Context) error { } // Get Hosts config - cluster.Hosts = make([]v1.RKEConfigHost, 0) + cluster.Nodes = make([]v1.RKEConfigNode, 0) for i := 0; i < numberOfHostsInt; i++ { hostCfg, err := getHostConfig(reader, i) if err != nil { return err } - cluster.Hosts = append(cluster.Hosts, *hostCfg) + cluster.Nodes = append(cluster.Nodes, *hostCfg) } // Get Network config @@ -129,27 +140,21 @@ func clusterConfig(ctx *cli.Context) error { return writeConfig(&cluster, configFile, print) } -func getHostConfig(reader *bufio.Reader, index int) (*v1.RKEConfigHost, error) { - host := v1.RKEConfigHost{} - advertisedHostname, err := getConfig(reader, fmt.Sprintf("Hostname of host (%d)", index+1), "") - if err != nil { - return nil, err - } - host.AdvertisedHostname = advertisedHostname - - sshIP, err := getConfig(reader, fmt.Sprintf("SSH IP of host (%s)", advertisedHostname), "") +func getHostConfig(reader *bufio.Reader, index int) (*v1.RKEConfigNode, error) { + host := v1.RKEConfigNode{} + address, err := getConfig(reader, fmt.Sprintf("SSH Address of host (%d)", index+1), "") if err != nil { return nil, err } - host.IP = sshIP + host.Address = address - advertisedIP, err := getConfig(reader, fmt.Sprintf("Advertised IP of host (%s)", advertisedHostname), "") + sshUser, err := getConfig(reader, fmt.Sprintf("SSH User of host (%s)", address), "ubuntu") if err != nil { return nil, err } - host.AdvertiseAddress = advertisedIP + host.User = sshUser - isControlHost, err := getConfig(reader, fmt.Sprintf("Is host (%s) a control host (y/n)?", advertisedHostname), "y") + isControlHost, err := getConfig(reader, fmt.Sprintf("Is host (%s) a control host (y/n)?", address), "y") if err != nil { return nil, err } @@ -157,7 +162,7 @@ func getHostConfig(reader *bufio.Reader, index int) (*v1.RKEConfigHost, error) { host.Role = append(host.Role, services.ControlRole) } - isWorkerHost, err := getConfig(reader, fmt.Sprintf("Is host (%s) a worker host (y/n)?", advertisedHostname), "n") + isWorkerHost, err := getConfig(reader, fmt.Sprintf("Is host (%s) a worker host (y/n)?", address), "n") if err != nil { return nil, err } @@ -165,7 +170,7 @@ func getHostConfig(reader *bufio.Reader, index int) (*v1.RKEConfigHost, error) { host.Role = append(host.Role, services.WorkerRole) } - isEtcdHost, err := getConfig(reader, fmt.Sprintf("Is host (%s) an Etcd host (y/n)?", advertisedHostname), "n") + isEtcdHost, err := getConfig(reader, fmt.Sprintf("Is host (%s) an Etcd host (y/n)?", address), "n") if err != nil { return nil, err } @@ -173,13 +178,19 @@ func getHostConfig(reader *bufio.Reader, index int) (*v1.RKEConfigHost, error) { host.Role = append(host.Role, services.ETCDRole) } - sshUser, err := getConfig(reader, fmt.Sprintf("SSH User of host (%s)", advertisedHostname), "ubuntu") + hostnameOverride, err := getConfig(reader, fmt.Sprintf("Override Hostname of host (%s)", address), "") if err != nil { return nil, err } - host.User = sshUser + host.HostnameOverride = hostnameOverride + + internalAddress, err := getConfig(reader, fmt.Sprintf("Internal IP of host (%s)", address), "") + if err != nil { + return nil, err + } + host.InternalAddress = internalAddress - dockerSocketPath, err := getConfig(reader, fmt.Sprintf("Docker socket path on host (%s)", advertisedHostname), "/var/run/docker.sock") + dockerSocketPath, err := getConfig(reader, fmt.Sprintf("Docker socket path on host (%s)", address), "/var/run/docker.sock") if err != nil { return nil, err } diff --git a/cmd/up.go b/cmd/up.go index 5a95c8005..61489b26e 100644 --- a/cmd/up.go +++ b/cmd/up.go @@ -89,7 +89,7 @@ func ClusterUp(clusterFile string) (string, string, string, string, error) { return APIURL, caCrt, clientCert, clientKey, err } - APIURL = fmt.Sprintf("https://" + kubeCluster.ControlPlaneHosts[0].IP + ":6443") + APIURL = fmt.Sprintf("https://" + kubeCluster.ControlPlaneHosts[0].Address + ":6443") caCrt = string(cert.EncodeCertPEM(kubeCluster.Certificates[pki.CACertName].Certificate)) clientCert = string(cert.EncodeCertPEM(kubeCluster.Certificates[pki.KubeAdminCommonName].Certificate)) clientKey = string(cert.EncodePrivateKeyPEM(kubeCluster.Certificates[pki.KubeAdminCommonName].Key)) diff --git a/hosts/dialer.go b/hosts/dialer.go index 614f82649..90011e870 100644 --- a/hosts/dialer.go +++ b/hosts/dialer.go @@ -21,7 +21,7 @@ const ( ) func (d *dialer) Dial(network, addr string) (net.Conn, error) { - sshAddr := d.host.IP + ":22" + sshAddr := d.host.Address + ":22" // Build SSH client configuration cfg, err := makeSSHConfig(d.host.User, d.signer) if err != nil { @@ -37,13 +37,13 @@ func (d *dialer) Dial(network, addr string) (net.Conn, error) { } remote, err := conn.Dial("unix", d.host.DockerSocket) if err != nil { - return nil, fmt.Errorf("Error connecting to Docker socket on host [%s]: %v", d.host.AdvertisedHostname, err) + return nil, fmt.Errorf("Error connecting to Docker socket on host [%s]: %v", d.host.Address, err) } return remote, err } func (h *Host) TunnelUp(signer ssh.Signer) error { - logrus.Infof("[ssh] Start tunnel for host [%s]", h.AdvertisedHostname) + logrus.Infof("[ssh] Start tunnel for host [%s]", h.Address) dialer := &dialer{ host: h, @@ -57,10 +57,10 @@ func (h *Host) TunnelUp(signer ssh.Signer) error { // set Docker client var err error - logrus.Debugf("Connecting to Docker API for host [%s]", h.AdvertisedHostname) + logrus.Debugf("Connecting to Docker API for host [%s]", h.Address) h.DClient, err = client.NewClient("unix:///var/run/docker.sock", DockerAPIVersion, httpClient, nil) if err != nil { - return fmt.Errorf("Can't connect to Docker for host [%s]: %v", h.AdvertisedHostname, err) + return fmt.Errorf("Can't connect to Docker for host [%s]: %v", h.Address, err) } return nil } diff --git a/hosts/hosts.go b/hosts/hosts.go index f013b0657..0bfa6311f 100644 --- a/hosts/hosts.go +++ b/hosts/hosts.go @@ -13,7 +13,7 @@ import ( ) type Host struct { - v1.RKEConfigHost + v1.RKEConfigNode DClient *client.Client } @@ -28,7 +28,7 @@ const ( ) func (h *Host) CleanUp() error { - logrus.Infof("[hosts] Cleaning up host [%s]", h.AdvertisedHostname) + logrus.Infof("[hosts] Cleaning up host [%s]", h.Address) toCleanDirs := []string{ ToCleanEtcdDir, ToCleanSSLDir, @@ -36,9 +36,9 @@ func (h *Host) CleanUp() error { ToCleanCNIBin, ToCleanCalicoRun, } - logrus.Infof("[hosts] Running cleaner container on host [%s]", h.AdvertisedHostname) + logrus.Infof("[hosts] Running cleaner container on host [%s]", h.Address) imageCfg, hostCfg := buildCleanerConfig(h, toCleanDirs) - if err := docker.DoRunContainer(h.DClient, imageCfg, hostCfg, CleanerContainerName, h.AdvertisedHostname, CleanerContainerName); err != nil { + if err := docker.DoRunContainer(h.DClient, imageCfg, hostCfg, CleanerContainerName, h.Address, CleanerContainerName); err != nil { return err } @@ -46,26 +46,26 @@ func (h *Host) CleanUp() error { return err } - logrus.Infof("[hosts] Removing cleaner container on host [%s]", h.AdvertisedHostname) - if err := docker.RemoveContainer(h.DClient, h.AdvertisedHostname, CleanerContainerName); err != nil { + logrus.Infof("[hosts] Removing cleaner container on host [%s]", h.Address) + if err := docker.RemoveContainer(h.DClient, h.Address, CleanerContainerName); err != nil { return err } - logrus.Infof("[hosts] Successfully cleaned up host [%s]", h.AdvertisedHostname) + logrus.Infof("[hosts] Successfully cleaned up host [%s]", h.Address) return nil } func DeleteNode(toDeleteHost *Host, kubeClient *kubernetes.Clientset) error { - logrus.Infof("[hosts] Cordoning host [%s]", toDeleteHost.AdvertisedHostname) - err := k8s.CordonUncordon(kubeClient, toDeleteHost.AdvertisedHostname, true) + logrus.Infof("[hosts] Cordoning host [%s]", toDeleteHost.Address) + err := k8s.CordonUncordon(kubeClient, toDeleteHost.HostnameOverride, true) if err != nil { return err } - logrus.Infof("[hosts] Deleting host [%s] from the cluster", toDeleteHost.AdvertisedHostname) - err = k8s.DeleteNode(kubeClient, toDeleteHost.AdvertisedHostname) + logrus.Infof("[hosts] Deleting host [%s] from the cluster", toDeleteHost.Address) + err = k8s.DeleteNode(kubeClient, toDeleteHost.HostnameOverride) if err != nil { return err } - logrus.Infof("[hosts] Successfully deleted host [%s] from the cluster", toDeleteHost.AdvertisedHostname) + logrus.Infof("[hosts] Successfully deleted host [%s] from the cluster", toDeleteHost.Address) return nil } @@ -74,7 +74,7 @@ func GetToDeleteHosts(currentHosts, configHosts []Host) []Host { for _, currentHost := range currentHosts { found := false for _, newHost := range configHosts { - if currentHost.AdvertisedHostname == newHost.AdvertisedHostname { + if currentHost.Address == newHost.Address { found = true } } @@ -90,8 +90,9 @@ func IsHostListChanged(currentHosts, configHosts []Host) bool { for _, host := range currentHosts { found := false for _, configHost := range configHosts { - if host.AdvertisedHostname == configHost.AdvertisedHostname { + if host.Address == configHost.Address { found = true + break } } if !found { @@ -101,8 +102,9 @@ func IsHostListChanged(currentHosts, configHosts []Host) bool { for _, host := range configHosts { found := false for _, currentHost := range currentHosts { - if host.AdvertisedHostname == currentHost.AdvertisedHostname { + if host.Address == currentHost.Address { found = true + break } } if !found { diff --git a/main.go b/main.go index a9fd5dcb6..d11833aa2 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,7 @@ import ( "github.com/urfave/cli" ) -var VERSION = "v0.0.2-dev" +var VERSION = "v0.0.6-dev" func main() { if err := mainErr(); err != nil { diff --git a/pki/deploy.go b/pki/deploy.go index 57d8280bf..c21435a3a 100644 --- a/pki/deploy.go +++ b/pki/deploy.go @@ -61,8 +61,8 @@ func DeployCertificatesOnWorkers(workerHosts []hosts.Host, crtMap map[string]Cer } func doRunDeployer(host *hosts.Host, containerEnv []string) error { - logrus.Debugf("[certificates] Pulling Certificate downloader Image on host [%s]", host.AdvertisedHostname) - err := docker.PullImage(host.DClient, host.AdvertisedHostname, CrtDownloaderImage) + logrus.Debugf("[certificates] Pulling Certificate downloader Image on host [%s]", host.Address) + err := docker.PullImage(host.DClient, host.Address, CrtDownloaderImage) if err != nil { return err } @@ -79,15 +79,15 @@ func doRunDeployer(host *hosts.Host, containerEnv []string) error { } resp, err := host.DClient.ContainerCreate(context.Background(), imageCfg, hostCfg, nil, CrtDownloaderContainer) if err != nil { - return fmt.Errorf("Failed to create Certificates deployer container on host [%s]: %v", host.AdvertisedHostname, err) + return fmt.Errorf("Failed to create Certificates deployer container on host [%s]: %v", host.Address, err) } if err := host.DClient.ContainerStart(context.Background(), resp.ID, types.ContainerStartOptions{}); err != nil { - return fmt.Errorf("Failed to start Certificates deployer container on host [%s]: %v", host.AdvertisedHostname, err) + return fmt.Errorf("Failed to start Certificates deployer container on host [%s]: %v", host.Address, err) } logrus.Debugf("[certificates] Successfully started Certificate deployer container: %s", resp.ID) for { - isDeployerRunning, err := docker.IsContainerRunning(host.DClient, host.AdvertisedHostname, CrtDownloaderContainer) + isDeployerRunning, err := docker.IsContainerRunning(host.DClient, host.Address, CrtDownloaderContainer) if err != nil { return err } @@ -96,7 +96,7 @@ func doRunDeployer(host *hosts.Host, containerEnv []string) error { continue } if err := host.DClient.ContainerRemove(context.Background(), resp.ID, types.ContainerRemoveOptions{}); err != nil { - return fmt.Errorf("Failed to delete Certificates deployer container on host[%s]: %v", host.AdvertisedHostname, err) + return fmt.Errorf("Failed to delete Certificates deployer container on host [%s]: %v", host.Address, err) } return nil } diff --git a/pki/pki.go b/pki/pki.go index 650e46225..ad7b17b34 100644 --- a/pki/pki.go +++ b/pki/pki.go @@ -167,7 +167,7 @@ func generateCerts(cpHosts []hosts.Host, clusterDomain, localConfigPath string, Certificate: kubeAdminCrt, Key: kubeAdminKey, Config: GetKubeConfigX509WithData( - "https://"+cpHosts[0].IP+":6443", + "https://"+cpHosts[0].Address+":6443", KubeAdminCommonName, string(cert.EncodeCertPEM(caCrt)), string(cert.EncodeCertPEM(kubeAdminCrt)), @@ -250,11 +250,25 @@ func GetAltNames(cpHosts []hosts.Host, clusterDomain string, KubernetesServiceIP ips := []net.IP{} dnsNames := []string{} for _, host := range cpHosts { - ips = append(ips, net.ParseIP(host.IP)) - if host.IP != host.AdvertiseAddress { - ips = append(ips, net.ParseIP(host.AdvertiseAddress)) + // Check if node address is a valid IP + if nodeIP := net.ParseIP(host.Address); nodeIP != nil { + ips = append(ips, nodeIP) + } else { + dnsNames = append(dnsNames, host.Address) + } + + // Check if node internal address is a valid IP + if len(host.InternalAddress) != 0 && host.InternalAddress != host.Address { + if internalIP := net.ParseIP(host.InternalAddress); internalIP != nil { + ips = append(ips, internalIP) + } else { + dnsNames = append(dnsNames, host.InternalAddress) + } + } + // Add hostname to the ALT dns names + if len(host.HostnameOverride) != 0 && host.HostnameOverride != host.Address { + dnsNames = append(dnsNames, host.HostnameOverride) } - dnsNames = append(dnsNames, host.AdvertisedHostname) } ips = append(ips, net.ParseIP("127.0.0.1")) ips = append(ips, KubernetesServiceIP) diff --git a/pki/pki_test.go b/pki/pki_test.go index 2e18e7305..fe4b4a08b 100644 --- a/pki/pki_test.go +++ b/pki/pki_test.go @@ -18,11 +18,11 @@ const ( func TestPKI(t *testing.T) { cpHosts := []hosts.Host{ hosts.Host{ - RKEConfigHost: v1.RKEConfigHost{ - IP: "1.1.1.1", - AdvertiseAddress: "192.168.1.5", - Role: []string{"controlplane"}, - AdvertisedHostname: "server1", + RKEConfigNode: v1.RKEConfigNode{ + Address: "1.1.1.1", + InternalAddress: "192.168.1.5", + Role: []string{"controlplane"}, + HostnameOverride: "server1", }, DClient: nil, }, @@ -73,8 +73,8 @@ func TestPKI(t *testing.T) { // Test ALT IPs kubeAPIAltIPs := []net.IP{ net.ParseIP("127.0.0.1"), - net.ParseIP(cpHosts[0].AdvertiseAddress), - net.ParseIP(cpHosts[0].IP), + net.ParseIP(cpHosts[0].InternalAddress), + net.ParseIP(cpHosts[0].Address), net.ParseIP(FakeKubernetesServiceIP), } diff --git a/services/etcd.go b/services/etcd.go index 0a7302834..bbc64e022 100644 --- a/services/etcd.go +++ b/services/etcd.go @@ -16,7 +16,7 @@ func RunEtcdPlane(etcdHosts []hosts.Host, etcdService v1.ETCDService) error { initCluster := getEtcdInitialCluster(etcdHosts) for _, host := range etcdHosts { imageCfg, hostCfg := buildEtcdConfig(host, etcdService, initCluster) - err := docker.DoRunContainer(host.DClient, imageCfg, hostCfg, EtcdContainerName, host.AdvertisedHostname, ETCDRole) + err := docker.DoRunContainer(host.DClient, imageCfg, hostCfg, EtcdContainerName, host.Address, ETCDRole) if err != nil { return err } @@ -28,7 +28,7 @@ func RunEtcdPlane(etcdHosts []hosts.Host, etcdService v1.ETCDService) error { func RemoveEtcdPlane(etcdHosts []hosts.Host) error { logrus.Infof("[%s] Tearing down Etcd Plane..", ETCDRole) for _, host := range etcdHosts { - err := docker.DoRemoveContainer(host.DClient, EtcdContainerName, host.AdvertisedHostname) + err := docker.DoRemoveContainer(host.DClient, EtcdContainerName, host.Address) if err != nil { return err } @@ -41,11 +41,11 @@ func buildEtcdConfig(host hosts.Host, etcdService v1.ETCDService, initCluster st imageCfg := &container.Config{ Image: etcdService.Image, Cmd: []string{"/usr/local/bin/etcd", - "--name=etcd-" + host.AdvertisedHostname, + "--name=etcd-" + host.HostnameOverride, "--data-dir=/etcd-data", - "--advertise-client-urls=http://" + host.AdvertiseAddress + ":2379,http://" + host.AdvertiseAddress + ":4001", + "--advertise-client-urls=http://" + host.InternalAddress + ":2379,http://" + host.InternalAddress + ":4001", "--listen-client-urls=http://0.0.0.0:2379", - "--initial-advertise-peer-urls=http://" + host.AdvertiseAddress + ":2380", + "--initial-advertise-peer-urls=http://" + host.InternalAddress + ":2380", "--listen-peer-urls=http://0.0.0.0:2380", "--initial-cluster-token=etcd-cluster-1", "--initial-cluster=" + initCluster, @@ -81,7 +81,7 @@ func buildEtcdConfig(host hosts.Host, etcdService v1.ETCDService, initCluster st func GetEtcdConnString(hosts []hosts.Host) string { connString := "" for i, host := range hosts { - connString += "http://" + host.AdvertiseAddress + ":2379" + connString += "http://" + host.InternalAddress + ":2379" if i < (len(hosts) - 1) { connString += "," } @@ -92,7 +92,7 @@ func GetEtcdConnString(hosts []hosts.Host) string { func getEtcdInitialCluster(hosts []hosts.Host) string { initialCluster := "" for i, host := range hosts { - initialCluster += fmt.Sprintf("etcd-%s=http://%s:2380", host.AdvertisedHostname, host.AdvertiseAddress) + initialCluster += fmt.Sprintf("etcd-%s=http://%s:2380", host.HostnameOverride, host.InternalAddress) if i < (len(hosts) - 1) { initialCluster += "," } diff --git a/services/kubeapi.go b/services/kubeapi.go index 8f5a2cf87..8b1e241b1 100644 --- a/services/kubeapi.go +++ b/services/kubeapi.go @@ -14,11 +14,11 @@ import ( func runKubeAPI(host hosts.Host, etcdHosts []hosts.Host, kubeAPIService v1.KubeAPIService) error { etcdConnString := GetEtcdConnString(etcdHosts) imageCfg, hostCfg := buildKubeAPIConfig(host, kubeAPIService, etcdConnString) - return docker.DoRunContainer(host.DClient, imageCfg, hostCfg, KubeAPIContainerName, host.AdvertisedHostname, ControlRole) + return docker.DoRunContainer(host.DClient, imageCfg, hostCfg, KubeAPIContainerName, host.Address, ControlRole) } func removeKubeAPI(host hosts.Host) error { - return docker.DoRemoveContainer(host.DClient, KubeAPIContainerName, host.AdvertisedHostname) + return docker.DoRemoveContainer(host.DClient, KubeAPIContainerName, host.Address) } func buildKubeAPIConfig(host hosts.Host, kubeAPIService v1.KubeAPIService, etcdConnString string) (*container.Config, *container.HostConfig) { @@ -26,17 +26,18 @@ func buildKubeAPIConfig(host hosts.Host, kubeAPIService v1.KubeAPIService, etcdC Image: kubeAPIService.Image, Entrypoint: []string{"kube-apiserver", "--insecure-bind-address=127.0.0.1", + "--bind-address=0.0.0.0", "--insecure-port=8080", "--secure-port=6443", "--cloud-provider=", "--allow_privileged=true", + "--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname", "--service-cluster-ip-range=" + kubeAPIService.ServiceClusterIPRange, "--admission-control=ServiceAccount,NamespaceLifecycle,LimitRanger,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds", "--runtime-config=batch/v2alpha1", "--runtime-config=authentication.k8s.io/v1beta1=true", "--storage-backend=etcd3", "--etcd-servers=" + etcdConnString, - "--advertise-address=" + host.AdvertiseAddress, "--client-ca-file=" + pki.CACertPath, "--tls-cert-file=" + pki.KubeAPICertPath, "--tls-private-key-file=" + pki.KubeAPIKeyPath, diff --git a/services/kubecontroller.go b/services/kubecontroller.go index 517dcf8cc..a8d30afda 100644 --- a/services/kubecontroller.go +++ b/services/kubecontroller.go @@ -12,11 +12,11 @@ import ( func runKubeController(host hosts.Host, kubeControllerService v1.KubeControllerService) error { imageCfg, hostCfg := buildKubeControllerConfig(kubeControllerService) - return docker.DoRunContainer(host.DClient, imageCfg, hostCfg, KubeControllerContainerName, host.AdvertisedHostname, ControlRole) + return docker.DoRunContainer(host.DClient, imageCfg, hostCfg, KubeControllerContainerName, host.Address, ControlRole) } func removeKubeController(host hosts.Host) error { - return docker.DoRemoveContainer(host.DClient, KubeControllerContainerName, host.AdvertisedHostname) + return docker.DoRemoveContainer(host.DClient, KubeControllerContainerName, host.Address) } func buildKubeControllerConfig(kubeControllerService v1.KubeControllerService) (*container.Config, *container.HostConfig) { diff --git a/services/kubelet.go b/services/kubelet.go index 980666695..4c50142c9 100644 --- a/services/kubelet.go +++ b/services/kubelet.go @@ -13,11 +13,11 @@ import ( func runKubelet(host hosts.Host, kubeletService v1.KubeletService, isMaster bool) error { imageCfg, hostCfg := buildKubeletConfig(host, kubeletService, isMaster) - return docker.DoRunContainer(host.DClient, imageCfg, hostCfg, KubeletContainerName, host.AdvertisedHostname, WorkerRole) + return docker.DoRunContainer(host.DClient, imageCfg, hostCfg, KubeletContainerName, host.Address, WorkerRole) } func removeKubelet(host hosts.Host) error { - return docker.DoRemoveContainer(host.DClient, KubeletContainerName, host.AdvertisedHostname) + return docker.DoRemoveContainer(host.DClient, KubeletContainerName, host.Address) } func buildKubeletConfig(host hosts.Host, kubeletService v1.KubeletService, isMaster bool) (*container.Config, *container.HostConfig) { @@ -27,11 +27,11 @@ func buildKubeletConfig(host hosts.Host, kubeletService v1.KubeletService, isMas "--v=2", "--address=0.0.0.0", "--cluster-domain=" + kubeletService.ClusterDomain, - "--hostname-override=" + host.AdvertisedHostname, "--pod-infra-container-image=" + kubeletService.InfraContainerImage, "--cgroup-driver=cgroupfs", "--cgroups-per-qos=True", "--enforce-node-allocatable=", + "--hostname-override=" + host.HostnameOverride, "--cluster-dns=" + kubeletService.ClusterDNSServer, "--network-plugin=cni", "--cni-conf-dir=/etc/cni/net.d", diff --git a/services/kubeproxy.go b/services/kubeproxy.go index d005f8ce9..fc1f67dd5 100644 --- a/services/kubeproxy.go +++ b/services/kubeproxy.go @@ -12,11 +12,11 @@ import ( func runKubeproxy(host hosts.Host, kubeproxyService v1.KubeproxyService) error { imageCfg, hostCfg := buildKubeproxyConfig(host, kubeproxyService) - return docker.DoRunContainer(host.DClient, imageCfg, hostCfg, KubeproxyContainerName, host.AdvertisedHostname, WorkerRole) + return docker.DoRunContainer(host.DClient, imageCfg, hostCfg, KubeproxyContainerName, host.Address, WorkerRole) } func removeKubeproxy(host hosts.Host) error { - return docker.DoRemoveContainer(host.DClient, KubeproxyContainerName, host.AdvertisedHostname) + return docker.DoRemoveContainer(host.DClient, KubeproxyContainerName, host.Address) } func buildKubeproxyConfig(host hosts.Host, kubeproxyService v1.KubeproxyService) (*container.Config, *container.HostConfig) { diff --git a/services/proxy.go b/services/proxy.go index 103f9cc5a..61de7f611 100644 --- a/services/proxy.go +++ b/services/proxy.go @@ -17,7 +17,7 @@ func RollingUpdateNginxProxy(cpHosts []hosts.Host, workerHosts []hosts.Host) err nginxProxyEnv := buildProxyEnv(cpHosts) for _, host := range workerHosts { imageCfg, hostCfg := buildNginxProxyConfig(host, nginxProxyEnv) - return docker.DoRollingUpdateContainer(host.DClient, imageCfg, hostCfg, NginxProxyContainerName, host.AdvertisedHostname, WorkerRole) + return docker.DoRollingUpdateContainer(host.DClient, imageCfg, hostCfg, NginxProxyContainerName, host.Address, WorkerRole) } return nil } @@ -25,11 +25,11 @@ func RollingUpdateNginxProxy(cpHosts []hosts.Host, workerHosts []hosts.Host) err func runNginxProxy(host hosts.Host, cpHosts []hosts.Host) error { nginxProxyEnv := buildProxyEnv(cpHosts) imageCfg, hostCfg := buildNginxProxyConfig(host, nginxProxyEnv) - return docker.DoRunContainer(host.DClient, imageCfg, hostCfg, NginxProxyContainerName, host.AdvertisedHostname, WorkerRole) + return docker.DoRunContainer(host.DClient, imageCfg, hostCfg, NginxProxyContainerName, host.Address, WorkerRole) } func removeNginxProxy(host hosts.Host) error { - return docker.DoRemoveContainer(host.DClient, NginxProxyContainerName, host.AdvertisedHostname) + return docker.DoRemoveContainer(host.DClient, NginxProxyContainerName, host.Address) } func buildNginxProxyConfig(host hosts.Host, nginxProxyEnv string) (*container.Config, *container.HostConfig) { @@ -48,7 +48,7 @@ func buildNginxProxyConfig(host hosts.Host, nginxProxyEnv string) (*container.Co func buildProxyEnv(cpHosts []hosts.Host) string { proxyEnv := "" for i, cpHost := range cpHosts { - proxyEnv += fmt.Sprintf("%s", cpHost.AdvertiseAddress) + proxyEnv += fmt.Sprintf("%s", cpHost.InternalAddress) if i < (len(cpHosts) - 1) { proxyEnv += "," } diff --git a/services/scheduler.go b/services/scheduler.go index 515d0a8b8..10efdb1cc 100644 --- a/services/scheduler.go +++ b/services/scheduler.go @@ -12,11 +12,11 @@ import ( func runScheduler(host hosts.Host, schedulerService v1.SchedulerService) error { imageCfg, hostCfg := buildSchedulerConfig(host, schedulerService) - return docker.DoRunContainer(host.DClient, imageCfg, hostCfg, SchedulerContainerName, host.AdvertisedHostname, ControlRole) + return docker.DoRunContainer(host.DClient, imageCfg, hostCfg, SchedulerContainerName, host.Address, ControlRole) } func removeScheduler(host hosts.Host) error { - return docker.DoRemoveContainer(host.DClient, SchedulerContainerName, host.AdvertisedHostname) + return docker.DoRemoveContainer(host.DClient, SchedulerContainerName, host.Address) } func buildSchedulerConfig(host hosts.Host, schedulerService v1.SchedulerService) (*container.Config, *container.HostConfig) { diff --git a/vendor.conf b/vendor.conf index 30379347a..b5ca727cd 100644 --- a/vendor.conf +++ b/vendor.conf @@ -10,12 +10,12 @@ github.com/docker/distribution 3800056b8832cf6075e78b282ac010131d8687b github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d github.com/docker/go-units 0dadbb0345b35ec7ef35e228dabb8de89a65bf52 golang.org/x/net 186fd3fc8194a5e9980a82230d69c1ff7134229f -github.com/rancher/types a7111733a50d97a2541c72e794d216105a22b972 +github.com/rancher/types 0a0a5647cfdec48e7f531534d383e755fae7861c github.com/opencontainers/go-digest 279bed98673dd5bef374d3b6e4b09e2af76183bf github.com/gogo/protobuf 117892bf1866fbaa2318c03e50e40564c8845457 github.com/opencontainers/image-spec 7c889fafd04a893f5c5f50b7ab9963d5d64e5242 github.com/pkg/errors f15c970de5b76fac0b59abb32d62c17cc7bed265 -github.com/rancher/norman 068b9eb94326e2c566c5eed7636163b1b407c4c0 +github.com/rancher/norman faa1fb2148211044253fc2f6403008958c72b1f0 gopkg.in/check.v1 11d3bc7aa68e238947792f30573146a3231fc0f1 k8s.io/api/core/v1 4df58c811fe2e65feb879227b2b245e4dc26e7ad k8s.io/client-go v5.0.0 transitive=true