diff --git a/pkg/master/master.go b/pkg/master/master.go index 0ff460f5972..64b46206ca6 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -707,6 +707,13 @@ func (m *Master) ListThirdPartyResources() []string { return result } +func (m *Master) hasThirdPartyResourceStorage(path string) bool { + m.thirdPartyResourcesLock.Lock() + defer m.thirdPartyResourcesLock.Unlock() + _, found := m.thirdPartyResources[path] + return found +} + func (m *Master) addThirdPartyResourceStorage(path string, storage *thirdpartyresourcedataetcd.REST, apiGroup unversioned.APIGroup) { m.thirdPartyResourcesLock.Lock() defer m.thirdPartyResourcesLock.Unlock() @@ -731,12 +738,19 @@ func (m *Master) InstallThirdPartyResource(rsrc *extensions.ThirdPartyResource) Version: rsrc.Versions[0].Name, Kind: kind, }) + path := makeThirdPartyPath(group) thirdparty := m.thirdpartyapi(group, kind, rsrc.Versions[0].Name, plural.Resource) - if err := thirdparty.InstallREST(m.HandlerContainer); err != nil { - glog.Fatalf("Unable to setup thirdparty api: %v", err) + + // If storage exists, this group has already been added, just update + // the group with the new API + if m.hasThirdPartyResourceStorage(path) { + return thirdparty.UpdateREST(m.HandlerContainer) + } + + if err := thirdparty.InstallREST(m.HandlerContainer); err != nil { + glog.Errorf("Unable to setup thirdparty api: %v", err) } - path := makeThirdPartyPath(group) groupVersion := unversioned.GroupVersionForDiscovery{ GroupVersion: group + "/" + rsrc.Versions[0].Name, Version: rsrc.Versions[0].Name, diff --git a/pkg/master/master_test.go b/pkg/master/master_test.go index 0c9faf4161a..a52e31ca83b 100644 --- a/pkg/master/master_test.go +++ b/pkg/master/master_test.go @@ -552,27 +552,77 @@ type FooList struct { } func initThirdParty(t *testing.T, version, name string) (*Master, *etcdtesting.EtcdTestServer, *httptest.Server, *assert.Assertions) { + return initThirdPartyMultiple(t, []string{version}, []string{name}) +} + +func initThirdPartyMultiple(t *testing.T, versions, names []string) (*Master, *etcdtesting.EtcdTestServer, *httptest.Server, *assert.Assertions) { master, etcdserver, _, assert := newMaster(t) - api := &extensions.ThirdPartyResource{ - ObjectMeta: api.ObjectMeta{ - Name: name, - }, - Versions: []extensions.APIVersion{ - { - Name: version, - }, - }, - } _, master.ServiceClusterIPRange, _ = net.ParseCIDR("10.0.0.0/24") - if !assert.NoError(master.InstallThirdPartyResource(api)) { - t.FailNow() + for ix := range names { + api := &extensions.ThirdPartyResource{ + ObjectMeta: api.ObjectMeta{ + Name: names[ix], + }, + Versions: []extensions.APIVersion{ + { + Name: versions[ix], + }, + }, + } + err := master.InstallThirdPartyResource(api) + if !assert.NoError(err) { + t.Logf("Failed to install API: %v", err) + t.FailNow() + } } server := httptest.NewServer(master.HandlerContainer.ServeMux) return master, etcdserver, server, assert } +func TestInstallMultipleAPIs(t *testing.T) { + names := []string{"foo.company.com", "bar.company.com"} + versions := []string{"v1", "v1"} + + _, etcdserver, server, assert := initThirdPartyMultiple(t, versions, names) + defer server.Close() + defer etcdserver.Terminate(t) + for ix := range names { + kind, group, err := thirdpartyresourcedata.ExtractApiGroupAndKind( + &extensions.ThirdPartyResource{ObjectMeta: api.ObjectMeta{Name: names[ix]}}) + assert.NoError(err, "Failed to extract group & kind") + + plural, _ := meta.KindToResource(unversioned.GroupVersionKind{ + Group: group, + Version: versions[ix], + Kind: kind, + }) + + resp, err := http.Get( + fmt.Sprintf("%s/apis/%s/%s/namespaces/default/%s", server.URL, group, versions[ix], plural.Resource)) + if !assert.NoError(err, "Failed to do HTTP GET") { + return + } + defer resp.Body.Close() + + assert.Equal(http.StatusOK, resp.StatusCode) + + data, err := ioutil.ReadAll(resp.Body) + assert.NoError(err) + + obj := map[string]interface{}{} + if err = json.Unmarshal(data, &obj); err != nil { + assert.NoError(err, fmt.Sprintf("unexpected error: %v", err)) + } + kindOut, found := obj["kind"] + if !found { + t.Errorf("Missing 'kind' in %v", obj) + } + assert.Equal(kindOut, kind+"List") + } +} + func TestInstallThirdPartyAPIList(t *testing.T) { for _, version := range versionsToTest { testInstallThirdPartyAPIListVersion(t, version)