diff --git a/cns/api.go b/cns/api.go index 97a2fe576e..42ed300fa3 100644 --- a/cns/api.go +++ b/cns/api.go @@ -18,6 +18,7 @@ const ( GetIPAddressUtilizationPath = "/network/ip/utilization" GetUnhealthyIPAddressesPath = "/network/ipaddresses/unhealthy" GetHealthReportPath = "/network/health" + NumberOfCPUCoresPath = "/hostcpucores" V1Prefix = "/v0.1" V2Prefix = "/v0.2" ) @@ -139,6 +140,12 @@ type Response struct { Message string } +// NumOfCPUCoresResponse describes num of cpu cores present on host. +type NumOfCPUCoresResponse struct { + Response Response + NumOfCPUCores int +} + // OptionMap describes generic options that can be passed to CNS. type OptionMap map[string]interface{} diff --git a/cns/restserver/api.go b/cns/restserver/api.go index 06ffc119ee..62c3bc4f85 100644 --- a/cns/restserver/api.go +++ b/cns/restserver/api.go @@ -21,6 +21,7 @@ const ( UnknownContainerID = 18 UnsupportedOrchestratorType = 19 DockerContainerNotSpecified = 20 + UnsupportedVerb = 21 UnexpectedError = 99 ) diff --git a/cns/restserver/restserver.go b/cns/restserver/restserver.go index e22b67ad66..b6a6853733 100644 --- a/cns/restserver/restserver.go +++ b/cns/restserver/restserver.go @@ -8,6 +8,7 @@ import ( "fmt" "net" "net/http" + "runtime" "sync" "time" @@ -157,6 +158,7 @@ func (service *HTTPRestService) Start(config *common.ServiceConfig) error { listener.AddHandler(cns.DetachContainerFromNetwork, service.detachNetworkContainerFromNetwork) listener.AddHandler(cns.CreateHnsNetworkPath, service.createHnsNetwork) listener.AddHandler(cns.DeleteHnsNetworkPath, service.deleteHnsNetwork) + listener.AddHandler(cns.NumberOfCPUCoresPath, service.getNumberOfCPUCores) // handlers for v0.2 listener.AddHandler(cns.V2Prefix+cns.SetEnvironmentPath, service.setEnvironment) @@ -177,6 +179,7 @@ func (service *HTTPRestService) Start(config *common.ServiceConfig) error { listener.AddHandler(cns.V2Prefix+cns.DetachContainerFromNetwork, service.detachNetworkContainerFromNetwork) listener.AddHandler(cns.V2Prefix+cns.CreateHnsNetworkPath, service.createHnsNetwork) listener.AddHandler(cns.V2Prefix+cns.DeleteHnsNetworkPath, service.deleteHnsNetwork) + listener.AddHandler(cns.V2Prefix+cns.NumberOfCPUCoresPath, service.getNumberOfCPUCores) log.Printf("[Azure CNS] Listening.") return nil @@ -1573,3 +1576,34 @@ func (service *HTTPRestService) getNetPluginDetails() *networkcontainers.NetPlug configPath, _ := service.GetOption(acn.OptNetPluginConfigFile).(string) return networkcontainers.NewNetPluginConfiguration(pluginBinPath, configPath) } + +// Retrieves the number of logic processors on a node. It will be primarily +// used to enforce per VM delegated NIC limit by DNC. +func (service *HTTPRestService) getNumberOfCPUCores(w http.ResponseWriter, r *http.Request) { + log.Printf("[Azure-CNS] getNumberOfCPUCores") + log.Request(service.Name, "getNumberOfCPUCores", nil) + + var ( + num int + returnCode int + errMsg string + ) + + switch r.Method { + case "GET": + num = runtime.NumCPU() + default: + errMsg = "[Azure-CNS] getNumberOfCPUCores API expects a GET." + returnCode = UnsupportedVerb + } + + resp := cns.Response{ReturnCode: returnCode, Message: errMsg} + numOfCPUCoresResp := cns.NumOfCPUCoresResponse{ + Response: resp, + NumOfCPUCores: num, + } + + err := service.Listener.Encode(w, &numOfCPUCoresResp) + + log.Response(service.Name, numOfCPUCoresResp, resp.ReturnCode, ReturnCodeToString(resp.ReturnCode), err) +} diff --git a/cns/restserver/restserver_test.go b/cns/restserver/restserver_test.go index b55c11d4e3..5580681035 100644 --- a/cns/restserver/restserver_test.go +++ b/cns/restserver/restserver_test.go @@ -689,3 +689,29 @@ func TestGetInterfaceForNetworkContainer(t *testing.T) { t.Fatal(err) } } + +func TestGetNumOfCPUCores(t *testing.T) { + fmt.Println("Test: getNumberOfCPUCores") + + var ( + err error + req *http.Request + ) + + req, err = http.NewRequest(http.MethodGet, cns.NumberOfCPUCoresPath, nil) + if err != nil { + t.Fatal(err) + } + + var w *httptest.ResponseRecorder + w = httptest.NewRecorder() + mux.ServeHTTP(w, req) + var numOfCoresResponse cns.NumOfCPUCoresResponse + + err = decodeResponse(w, &numOfCoresResponse) + if err != nil || numOfCoresResponse.Response.ReturnCode != 0 { + t.Errorf("getNumberOfCPUCores failed with response %+v", numOfCoresResponse) + } else { + fmt.Printf("getNumberOfCPUCores Responded with %+v\n", numOfCoresResponse) + } +}