Skip to content

Commit

Permalink
Merge pull request #1 from virtual-kubelet/aci-gpu-client
Browse files Browse the repository at this point in the history
ACI GPU Support Changes in Client
  • Loading branch information
cpuguy83 authored Mar 29, 2019
2 parents a416451 + 655515e commit a846478
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 43 deletions.
2 changes: 2 additions & 0 deletions client/aci/analytics.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io/ioutil"
)

// NewContainerGroupDiagnostics creates a container group diagnostics object
func NewContainerGroupDiagnostics(logAnalyticsID, logAnalyticsKey string) (*ContainerGroupDiagnostics, error) {

if logAnalyticsID == "" || logAnalyticsKey == "" {
Expand All @@ -21,6 +22,7 @@ func NewContainerGroupDiagnostics(logAnalyticsID, logAnalyticsKey string) (*Cont
}, nil
}

// NewContainerGroupDiagnosticsFromFile creates a container group diagnostics object from the specified file
func NewContainerGroupDiagnosticsFromFile(filepath string) (*ContainerGroupDiagnostics, error) {

analyticsdata, err := ioutil.ReadFile(filepath)
Expand Down
4 changes: 2 additions & 2 deletions client/aci/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import (
const (
// BaseURI is the default URI used for compute services.
baseURI = "https://management.azure.com"
defaultUserAgent = "virtual-kubelet/azure-arm-aci/2018-09-01"
apiVersion = "2018-09-01"
defaultUserAgent = "virtual-kubelet/azure-arm-aci/2018-10-01"
apiVersion = "2018-10-01"

containerGroupURLPath = "subscriptions/{{.subscriptionId}}/resourceGroups/{{.resourceGroup}}/providers/Microsoft.ContainerInstance/containerGroups/{{.containerGroupName}}"
containerGroupListURLPath = "subscriptions/{{.subscriptionId}}/providers/Microsoft.ContainerInstance/containerGroups"
Expand Down
95 changes: 75 additions & 20 deletions client/aci/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func TestCreateContainerGroupWithoutResourceLimit(t *testing.T) {
},
},
Resources: ResourceRequirements{
Requests: &ResourceRequests{
Requests: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Expand Down Expand Up @@ -179,11 +179,11 @@ func TestCreateContainerGroup(t *testing.T) {
},
},
Resources: ResourceRequirements{
Requests: &ResourceRequests{
Requests: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Limits: &ResourceLimits{
Limits: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Expand Down Expand Up @@ -219,11 +219,11 @@ func TestCreateContainerGroupWithBadVNetFails(t *testing.T) {
},
},
Resources: ResourceRequirements{
Requests: &ResourceRequests{
Requests: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Limits: &ResourceLimits{
Limits: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Expand Down Expand Up @@ -251,7 +251,7 @@ func TestCreateContainerGroupWithBadVNetFails(t *testing.T) {
}

func TestGetContainerGroup(t *testing.T) {
cg, err, _ := client.GetContainerGroup(context.Background(), resourceGroup, containerGroup)
cg, _, err := client.GetContainerGroup(context.Background(), resourceGroup, containerGroup)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -292,11 +292,11 @@ func TestCreateContainerGroupWithLivenessProbe(t *testing.T) {
},
},
Resources: ResourceRequirements{
Requests: &ResourceRequests{
Requests: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Limits: &ResourceLimits{
Limits: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Expand Down Expand Up @@ -339,11 +339,11 @@ func TestCreateContainerGroupFailsWithLivenessProbeMissingPort(t *testing.T) {
},
},
Resources: ResourceRequirements{
Requests: &ResourceRequests{
Requests: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Limits: &ResourceLimits{
Limits: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Expand Down Expand Up @@ -383,11 +383,11 @@ func TestCreateContainerGroupWithReadinessProbe(t *testing.T) {
},
},
Resources: ResourceRequirements{
Requests: &ResourceRequests{
Requests: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Limits: &ResourceLimits{
Limits: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Expand Down Expand Up @@ -438,11 +438,11 @@ func TestCreateContainerGroupWithLogAnalytics(t *testing.T) {
},
},
Resources: ResourceRequirements{
Requests: &ResourceRequests{
Requests: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Limits: &ResourceLimits{
Limits: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Expand Down Expand Up @@ -483,11 +483,11 @@ func TestCreateContainerGroupWithInvalidLogAnalytics(t *testing.T) {
},
},
Resources: ResourceRequirements{
Requests: &ResourceRequests{
Requests: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Limits: &ResourceLimits{
Limits: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Expand All @@ -509,7 +509,7 @@ func TestCreateContainerGroupWithVNet(t *testing.T) {
uid := uuid.New()
containerGroupName := containerGroup + "-" + uid.String()[0:6]
fakeKubeConfig := base64.StdEncoding.EncodeToString([]byte(uid.String()))
networkProfileId := "/subscriptions/ae43b1e3-c35d-4c8c-bc0d-f148b4c52b78/resourceGroups/aci-connector/providers/Microsoft.Network/networkprofiles/aci-connector-network-profile-westus"
networkProfileID := "/subscriptions/ae43b1e3-c35d-4c8c-bc0d-f148b4c52b78/resourceGroups/aci-connector/providers/Microsoft.Network/networkprofiles/aci-connector-network-profile-westus"
diagnostics, err := NewContainerGroupDiagnosticsFromFile(os.Getenv("LOG_ANALYTICS_AUTH_LOCATION"))
if err != nil {
t.Fatal(err)
Expand All @@ -534,11 +534,11 @@ func TestCreateContainerGroupWithVNet(t *testing.T) {
},
},
Resources: ResourceRequirements{
Requests: &ResourceRequests{
Requests: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Limits: &ResourceLimits{
Limits: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
},
Expand All @@ -547,7 +547,7 @@ func TestCreateContainerGroupWithVNet(t *testing.T) {
},
},
NetworkProfile: &NetworkProfileDefinition{
ID: networkProfileId,
ID: networkProfileID,
},
Extensions: []*Extension{
&Extension{
Expand Down Expand Up @@ -583,6 +583,61 @@ func TestCreateContainerGroupWithVNet(t *testing.T) {
}
}

func TestCreateContainerGroupWithGPU(t *testing.T) {
uid := uuid.New()
containerGroupName := containerGroup + "-" + uid.String()[0:6]

cg, err := client.CreateContainerGroup(context.Background(), resourceGroup, containerGroupName, ContainerGroup{
Location: "eastus",
ContainerGroupProperties: ContainerGroupProperties{
OsType: Linux,
Containers: []Container{
{
Name: "nginx",
ContainerProperties: ContainerProperties{
Image: "nginx",
Command: []string{"nginx", "-g", "daemon off;"},
Ports: []ContainerPort{
{
Protocol: ContainerNetworkProtocolTCP,
Port: 80,
},
},
Resources: ResourceRequirements{
Requests: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
GPU: &GPUResource{
Count: 1,
SKU: GPUSKU("K80"),
},
},
Limits: &ComputeResources{
CPU: 1,
MemoryInGB: 1,
GPU: &GPUResource{
Count: 1,
SKU: GPUSKU("K80"),
},
},
},
},
},
},
},
})

if err != nil {
t.Fatal(err)
}
if cg.Name != containerGroupName {
t.Fatalf("resource group name is %s, expected %s", cg.Name, containerGroupName)
}
if err := client.DeleteContainerGroup(context.Background(), resourceGroup, containerGroupName); err != nil {
t.Fatalf("Delete Container Group failed: %s", err.Error())
}
}

func TestDeleteContainerGroup(t *testing.T) {
err := client.DeleteContainerGroup(context.Background(), resourceGroup, containerGroup)
if err != nil {
Expand Down
5 changes: 3 additions & 2 deletions client/aci/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import (
"github.com/virtual-kubelet/azure-aci/client/api"
)

// TerminalSizeRequest is the terminal size request
type TerminalSizeRequest struct {
Width int
Height int
}

// Starts the exec command for a specified container instance in a specified resource group and container group.
// LaunchExec starts the exec command for a specified container instance in a specified resource group and container group.
// From: https://docs.microsoft.com/en-us/rest/api/container-instances/startcontainer/launchexec
func (c *Client) LaunchExec(resourceGroup, containerGroupName, containerName, command string, terminalSize TerminalSizeRequest) (ExecResponse, error) {
urlParams := url.Values{
Expand All @@ -35,7 +36,7 @@ func (c *Client) LaunchExec(resourceGroup, containerGroupName, containerName, co

var xcrsp ExecResponse
xcrsp.Password = ""
xcrsp.WebSocketUri = ""
xcrsp.WebSocketURI = ""

b := new(bytes.Buffer)

Expand Down
16 changes: 8 additions & 8 deletions client/aci/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
// GetContainerGroup gets an Azure Container Instance in the provided
// resource group with the given container group name.
// From: https://docs.microsoft.com/en-us/rest/api/container-instances/containergroups/get
func (c *Client) GetContainerGroup(ctx context.Context, resourceGroup, containerGroupName string) (*ContainerGroup, error, *int) {
func (c *Client) GetContainerGroup(ctx context.Context, resourceGroup, containerGroupName string) (*ContainerGroup, *int, error) {
urlParams := url.Values{
"api-version": []string{apiVersion},
}
Expand All @@ -26,7 +26,7 @@ func (c *Client) GetContainerGroup(ctx context.Context, resourceGroup, container
// Create the request.
req, err := http.NewRequest("GET", uri, nil)
if err != nil {
return nil, fmt.Errorf("Creating get container group uri request failed: %v", err), nil
return nil, nil, fmt.Errorf("Creating get container group uri request failed: %v", err)
}
req = req.WithContext(ctx)

Expand All @@ -36,29 +36,29 @@ func (c *Client) GetContainerGroup(ctx context.Context, resourceGroup, container
"resourceGroup": resourceGroup,
"containerGroupName": containerGroupName,
}); err != nil {
return nil, fmt.Errorf("Expanding URL with parameters failed: %v", err), nil
return nil, nil, fmt.Errorf("Expanding URL with parameters failed: %v", err)
}

// Send the request.
resp, err := c.hc.Do(req)
if err != nil {
return nil, fmt.Errorf("Sending get container group request failed: %v", err), nil
return nil, nil, fmt.Errorf("Sending get container group request failed: %v", err)
}
defer resp.Body.Close()

// 200 (OK) is a success response.
if err := api.CheckResponse(resp); err != nil {
return nil, err, &resp.StatusCode
return nil, &resp.StatusCode, err
}

// Decode the body from the response.
if resp.Body == nil {
return nil, errors.New("Get container group returned an empty body in the response"), &resp.StatusCode
return nil, &resp.StatusCode, errors.New("Get container group returned an empty body in the response")
}
var cg ContainerGroup
if err := json.NewDecoder(resp.Body).Decode(&cg); err != nil {
return nil, fmt.Errorf("Decoding get container group response body failed: %v", err), &resp.StatusCode
return nil, &resp.StatusCode, fmt.Errorf("Decoding get container group response body failed: %v", err)
}

return &cg, nil, &resp.StatusCode
return &cg, &resp.StatusCode, nil
}
76 changes: 76 additions & 0 deletions client/aci/rp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package aci

import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"

"github.com/virtual-kubelet/azure-aci/client/api"
)

const (
resourceProviderURLPath = "providers/Microsoft.ContainerInstance"
resourceProviderAPIVersion = "2018-02-01"
)

// GetResourceProviderMetadata gets the ACI resource provider metadata
func (c *Client) GetResourceProviderMetadata(ctx context.Context) (*ResourceProviderMetadata, error) {
manifest, err := c.getResourceProviderManifest(ctx)
if err != nil {
return nil, err
}

if manifest == nil {
return nil, fmt.Errorf("The resource provider manifest is empty")
}

if manifest.Metadata == nil {
return nil, fmt.Errorf("The resource provider metadata is empty")
}

return manifest.Metadata, nil
}

func (c *Client) getResourceProviderManifest(ctx context.Context) (*ResourceProviderManifest, error) {
urlParams := url.Values{
"api-version": []string{resourceProviderAPIVersion},
"$expand": []string{"metadata"},
}

// Create the url.
uri := api.ResolveRelative(c.auth.ResourceManagerEndpoint, resourceProviderURLPath)
uri += "?" + url.Values(urlParams).Encode()

// Create the request.
req, err := http.NewRequest("GET", uri, nil)
if err != nil {
return nil, fmt.Errorf("Creating get resource provider manifest request failed: %v", err)
}
req = req.WithContext(ctx)

// Send the request.
resp, err := c.hc.Do(req)
if err != nil {
return nil, fmt.Errorf("Sending get resource provider manifest request failed: %v", err)
}
defer resp.Body.Close()

// 200 (OK) is a success response.
if err := api.CheckResponse(resp); err != nil {
return nil, err
}

// Decode the body from the response.
if resp.Body == nil {
return nil, errors.New("Get resource provider manifest returned an empty body in the response")
}
var manifest ResourceProviderManifest
if err := json.NewDecoder(resp.Body).Decode(&manifest); err != nil {
return nil, fmt.Errorf("Decoding get resource provider manifest response body failed: %v", err)
}

return &manifest, nil
}
Loading

0 comments on commit a846478

Please sign in to comment.