From 55ed32e9247d33dc55a327993b77c548eb7d2ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= Date: Wed, 11 May 2022 10:37:58 +0200 Subject: [PATCH] clh: Take care of the VmAdNetdPut request ourselves MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Knowing that VmAddNetPut works as expected, let's switch to manually building the request and writing it to the appropriate socket. By doing this it gives us more flexibility to, later on, pass the file descriptor of the tuntap device to Cloud Hypervisor, as openAPI doesn't support such operation (it has no notion of SCM Rights). Signed-off-by: Fabiano FidĂȘncio --- src/runtime/virtcontainers/clh.go | 73 +++++++++++++++++++++----- src/runtime/virtcontainers/clh_test.go | 9 +--- 2 files changed, 63 insertions(+), 19 deletions(-) diff --git a/src/runtime/virtcontainers/clh.go b/src/runtime/virtcontainers/clh.go index 1016bcb8e0..5d290ff3bc 100644 --- a/src/runtime/virtcontainers/clh.go +++ b/src/runtime/virtcontainers/clh.go @@ -9,11 +9,15 @@ package virtcontainers import ( + "bufio" + "bytes" "context" "encoding/json" "fmt" + "io/ioutil" "net" "net/http" + "net/http/httputil" "os" "os/exec" "path/filepath" @@ -99,8 +103,6 @@ type clhClient interface { VmAddDiskPut(ctx context.Context, diskConfig chclient.DiskConfig) (chclient.PciDeviceInfo, *http.Response, error) // Remove a device from the VM VmRemoveDevicePut(ctx context.Context, vmRemoveDevice chclient.VmRemoveDevice) (*http.Response, error) - // Add a new net device to the VM - VmAddNetPut(ctx context.Context, netConfig chclient.NetConfig) (chclient.PciDeviceInfo, *http.Response, error) } type clhClientApi struct { @@ -144,20 +146,67 @@ func (c *clhClientApi) VmRemoveDevicePut(ctx context.Context, vmRemoveDevice chc return c.ApiInternal.VmRemoveDevicePut(ctx).VmRemoveDevice(vmRemoveDevice).Execute() } -func (c *clhClientApi) VmAddNetPut(ctx context.Context, netConfig chclient.NetConfig) (chclient.PciDeviceInfo, *http.Response, error) { - return c.ApiInternal.VmAddNetPut(ctx).NetConfig(netConfig).Execute() -} - // This is done in order to be able to override such a function as part of // our unit tests, as when testing bootVM we're on a mocked scenario already. -var vmAddNetPutRequest = func(clh *cloudHypervisor, ctx context.Context) error { - cl := clh.client() +var vmAddNetPutRequest = func(clh *cloudHypervisor) error { + addr, err := net.ResolveUnixAddr("unix", clh.state.apiSocket) + if err != nil { + return err + } + + conn, err := net.DialUnix("unix", nil, addr) + if err != nil { + return err + } + defer conn.Close() for _, netDevice := range *clh.netDevices { - _, _, err := cl.VmAddNetPut(ctx, netDevice) + netDeviceAsJson, err := json.Marshal(netDevice) if err != nil { return err } + netDeviceAsIoReader := bytes.NewBuffer(netDeviceAsJson) + + req, err := http.NewRequest(http.MethodPut, "http://localhost/api/v1/vm.add-net", netDeviceAsIoReader) + if err != nil { + return err + } + + req.Header.Set("Accept", "application/json") + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Content-Length", strconv.Itoa(int(netDeviceAsIoReader.Len()))) + + payload, err := httputil.DumpRequest(req, true) + if err != nil { + return err + } + + payloadn, err := conn.Write([]byte(payload)) + if err != nil { + return err + } + if payloadn != len(payload) { + return fmt.Errorf("Failed to send all the request to Cloud Hypervisor. %d bytes expect to send, but only %d sent", len(payload), payloadn) + } + + reader := bufio.NewReader(conn) + resp, err := http.ReadResponse(reader, req) + if err != nil { + return err + } + + respBody, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + resp.Body.Close() + resp.Body = ioutil.NopCloser(bytes.NewBuffer(respBody)) + + if resp.StatusCode != 204 { + clh.Logger().Errorf("vmAddNetPut failed with error '%d'. Response: %+v", resp.StatusCode, resp) + return fmt.Errorf("Failed to add the network device '%+v' to Cloud Hypervisor: %v", netDevice, resp.StatusCode) + } } return nil @@ -1283,8 +1332,8 @@ func openAPIClientError(err error) error { return fmt.Errorf("error: %v reason: %s", err, reason) } -func (clh *cloudHypervisor) vmAddNetPut(ctx context.Context) error { - return vmAddNetPutRequest(clh, ctx) +func (clh *cloudHypervisor) vmAddNetPut() error { + return vmAddNetPutRequest(clh) } func (clh *cloudHypervisor) bootVM(ctx context.Context) error { @@ -1314,7 +1363,7 @@ func (clh *cloudHypervisor) bootVM(ctx context.Context) error { return fmt.Errorf("VM state is not 'Created' after 'CreateVM'") } - err = clh.vmAddNetPut(ctx) + err = clh.vmAddNetPut() if err != nil { return err } diff --git a/src/runtime/virtcontainers/clh_test.go b/src/runtime/virtcontainers/clh_test.go index b1108ab6c9..31ae67c1a9 100644 --- a/src/runtime/virtcontainers/clh_test.go +++ b/src/runtime/virtcontainers/clh_test.go @@ -117,11 +117,6 @@ func (c *clhClientMock) VmRemoveDevicePut(ctx context.Context, vmRemoveDevice ch return nil, nil } -//nolint:golint -func (c *clhClientMock) VmAddNetPut(ctx context.Context, netConfig chclient.NetConfig) (chclient.PciDeviceInfo, *http.Response, error) { - return chclient.PciDeviceInfo{}, nil, nil -} - func TestCloudHypervisorAddVSock(t *testing.T) { assert := assert.New(t) clh := cloudHypervisor{} @@ -380,7 +375,7 @@ func TestCloudHypervisorBootVM(t *testing.T) { clh.APIClient = &clhClientMock{} savedVmAddNetPutRequestFunc := vmAddNetPutRequest - vmAddNetPutRequest = func(clh *cloudHypervisor, ctx context.Context) error { return nil } + vmAddNetPutRequest = func(clh *cloudHypervisor) error { return nil } defer func() { vmAddNetPutRequest = savedVmAddNetPutRequestFunc }() @@ -499,7 +494,7 @@ func TestCloudHypervisorStartSandbox(t *testing.T) { assert.NoError(err) savedVmAddNetPutRequestFunc := vmAddNetPutRequest - vmAddNetPutRequest = func(clh *cloudHypervisor, ctx context.Context) error { return nil } + vmAddNetPutRequest = func(clh *cloudHypervisor) error { return nil } defer func() { vmAddNetPutRequest = savedVmAddNetPutRequestFunc }()