Skip to content

Commit

Permalink
Add test cases for serverExec (#200)
Browse files Browse the repository at this point in the history
  • Loading branch information
ushabelgur authored Mar 1, 2024
1 parent 4586453 commit f65182b
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 13 deletions.
9 changes: 8 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ require (
sigs.k8s.io/controller-runtime v0.17.2
)

require (
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
k8s.io/cli-runtime v0.29.2 // indirect
)

require (
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
Expand Down Expand Up @@ -120,9 +126,10 @@ require (
gotest.tools/v3 v3.5.1 // indirect
k8s.io/apiextensions-apiserver v0.29.1 // indirect
k8s.io/apiserver v0.29.1 // indirect
k8s.io/component-base v0.29.1 // indirect
k8s.io/component-base v0.29.2 // indirect
k8s.io/klog/v2 v2.120.1 // indirect
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
k8s.io/kubectl v0.29.2
oras.land/oras-go v1.2.4 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
Expand Down
12 changes: 10 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -178,13 +178,17 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
Expand Down Expand Up @@ -419,14 +423,18 @@ k8s.io/apimachinery v0.29.2 h1:EWGpfJ856oj11C52NRCHuU7rFDwxev48z+6DSlGNsV8=
k8s.io/apimachinery v0.29.2/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU=
k8s.io/apiserver v0.29.1 h1:e2wwHUfEmMsa8+cuft8MT56+16EONIEK8A/gpBSco+g=
k8s.io/apiserver v0.29.1/go.mod h1:V0EpkTRrJymyVT3M49we8uh2RvXf7fWC5XLB0P3SwRw=
k8s.io/cli-runtime v0.29.2 h1:smfsOcT4QujeghsNjECKN3lwyX9AwcFU0nvJ7sFN3ro=
k8s.io/cli-runtime v0.29.2/go.mod h1:KLisYYfoqeNfO+MkTWvpqIyb1wpJmmFJhioA0xd4MW8=
k8s.io/client-go v0.29.2 h1:FEg85el1TeZp+/vYJM7hkDlSTFZ+c5nnK44DJ4FyoRg=
k8s.io/client-go v0.29.2/go.mod h1:knlvFZE58VpqbQpJNbCbctTVXcd35mMyAAwBdpt4jrA=
k8s.io/component-base v0.29.1 h1:MUimqJPCRnnHsskTTjKD+IC1EHBbRCVyi37IoFBrkYw=
k8s.io/component-base v0.29.1/go.mod h1:fP9GFjxYrLERq1GcWWZAE3bqbNcDKDytn2srWuHTtKc=
k8s.io/component-base v0.29.2 h1:lpiLyuvPA9yV1aQwGLENYyK7n/8t6l3nn3zAtFTJYe8=
k8s.io/component-base v0.29.2/go.mod h1:BfB3SLrefbZXiBfbM+2H1dlat21Uewg/5qtKOl8degM=
k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
k8s.io/kubectl v0.29.2 h1:uaDYaBhumvkwz0S2XHt36fK0v5IdNgL7HyUniwb2IUo=
k8s.io/kubectl v0.29.2/go.mod h1:BhizuYBGcKaHWyq+G7txGw2fXg576QbPrrnQdQDZgqI=
k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ=
k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
libvirt.org/go/libvirtxml v1.10000.0 h1:KPZXcmqUoJaJai95et+TEZegUQkFzCJgf1A59BOWpZQ=
Expand Down
11 changes: 6 additions & 5 deletions provider/cmd/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,8 @@ import (
)

var (
homeDir string
scheme = runtime.NewScheme()
virshExecutable string
homeDir string
scheme = runtime.NewScheme()
)

func init() {
Expand Down Expand Up @@ -85,6 +84,8 @@ type Options struct {

GCVMGracefulShutdownTimeout time.Duration
ResyncIntervalGarbageCollector time.Duration

VirshExecutable string
}

type LibvirtOptions struct {
Expand All @@ -111,7 +112,7 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&o.BaseURL, "base-url", "", "The base url to construct urls for streaming from. If empty it will be "+
"constructed from the streaming-address")

fs.StringVar(&virshExecutable, "virsh-executable", "virsh", "Path / name of the virsh executable.")
fs.StringVar(&o.VirshExecutable, "virsh-executable", "virsh", "Path / name of the virsh executable.")

fs.BoolVar(&o.EnableHugepages, "enable-hugepages", false, "Enable using Hugepages.")

Expand Down Expand Up @@ -339,7 +340,7 @@ func Run(ctx context.Context, opts Options) error {
MachineClasses: machineClasses,
VolumePlugins: volumePlugins,
NetworkPlugins: nicPlugin,
VirshExecutable: virshExecutable,
VirshExecutable: opts.VirshExecutable,
EnableHugepages: opts.EnableHugepages,
})
if err != nil {
Expand Down
7 changes: 7 additions & 0 deletions provider/http/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,12 @@ var _ = Describe("HTTP Handler", func() {
Expect(recorder.Code).To(Equal(http.StatusNotFound))
})
})
It("should fail when http request with a not expected method called", func() {
req, err := http.NewRequest(http.MethodPut, "/exec/unknowntoken", nil)
Expect(err).NotTo(HaveOccurred())
recorder := httptest.NewRecorder()
router.ServeHTTP(recorder, req)
Expect(recorder.Code).To(Equal(http.StatusMethodNotAllowed))
})
})
})
83 changes: 79 additions & 4 deletions provider/server/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,27 @@
package server_test

import (
"bytes"
"context"
"fmt"
"net/http"
"net/url"
"time"

"github.com/digitalocean/go-libvirt"
iri "github.com/ironcore-dev/ironcore/iri/apis/machine/v1alpha1"
irimeta "github.com/ironcore-dev/ironcore/iri/apis/meta/v1alpha1"
libvirtutils "github.com/ironcore-dev/libvirt-provider/pkg/libvirt/utils"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/util/httpstream/spdy"
"k8s.io/client-go/tools/remotecommand"
"k8s.io/kubectl/pkg/util/term"
)

var _ = Describe("Exec", func() {

It("should return an exec-url with a token", func(ctx SpecContext) {
It("should verify an exec-url with a token", func(ctx SpecContext) {
By("creating the test machine")
createResp, err := machineClient.CreateMachine(ctx, &iri.CreateMachineRequest{
Machine: &iri.Machine{
Expand All @@ -30,9 +38,12 @@ var _ = Describe("Exec", func() {
Expect(createResp).NotTo(BeNil())

DeferCleanup(func(ctx SpecContext) {
_, err := machineClient.DeleteMachine(ctx, &iri.DeleteMachineRequest{MachineId: createResp.Machine.Metadata.Id})
Expect(err).ShouldNot(HaveOccurred())
Eventually(func() bool {
_, err := machineClient.DeleteMachine(ctx, &iri.DeleteMachineRequest{MachineId: createResp.Machine.Metadata.Id})
Expect(err).To(SatisfyAny(
BeNil(),
MatchError(ContainSubstring("NotFound")),
))
_, err = libvirtConn.DomainLookupByUUID(libvirtutils.UUIDStringToBytes(createResp.Machine.Metadata.Id))
return libvirt.IsNotFound(err)
}).Should(BeTrue())
Expand All @@ -55,7 +66,7 @@ var _ = Describe("Exec", func() {
return libvirt.DomainState(domainState)
}).Should(Equal(libvirt.DomainRunning))

By("issuing exec for the test machine")
By("getting exec-url for the test machine")
execResp, err := machineClient.Exec(ctx, &iri.ExecRequest{MachineId: createResp.Machine.Metadata.Id})
Expect(err).NotTo(HaveOccurred())

Expand All @@ -68,5 +79,69 @@ var _ = Describe("Exec", func() {
Expect(parsedResUrl.Host).To(Equal(parsedBaseURL.Host))
Expect(parsedResUrl.Scheme).To(Equal(parsedBaseURL.Scheme))
Expect(parsedResUrl.Path).To(MatchRegexp(`/exec/[^/?&]{8}`))

By("issuing exec with response URL received and verifying tty stream")
err = runExec(ctx, parsedResUrl)
Expect(err).NotTo(HaveOccurred())

By("Verifying same token cannot be used twice")
err = runExec(ctx, parsedResUrl)
Expect(err).To(MatchError(ContainSubstring("404 page not found")), "Rejecting unknown / expired token")

By("getting exec-url with new token")
execResp, err = machineClient.Exec(ctx, &iri.ExecRequest{MachineId: createResp.Machine.Metadata.Id})
Expect(err).NotTo(HaveOccurred())

By("inspecting the result")
parsedResUrl, err = url.ParseRequestURI(execResp.Url)
Expect(err).NotTo(HaveOccurred(), "url is invalid: %q", execResp.Url)

By("deleting the machine")
_, err = machineClient.DeleteMachine(ctx, &iri.DeleteMachineRequest{MachineId: createResp.Machine.Metadata.Id})
Expect(err).ShouldNot(HaveOccurred())
Eventually(func() bool {
_, err = libvirtConn.DomainLookupByUUID(libvirtutils.UUIDStringToBytes(createResp.Machine.Metadata.Id))
return libvirt.IsNotFound(err)
}).Should(BeTrue())

By("verifying exec url with a valid token and a not existing machine fails")
err = runExec(ctx, parsedResUrl)
machineNotSynchErr := fmt.Sprintf("machine %s has not yet been synced", createResp.Machine.Metadata.Id)
Expect(err).To(SatisfyAny(MatchError(ContainSubstring("404 page not found")), MatchError(ContainSubstring(machineNotSynchErr))))

})
})

func runExec(ctx context.Context, execUrl *url.URL) error {
randomSize := 1024 * 1024
randomData := make([]byte, randomSize)
var stdout bytes.Buffer

tty := term.TTY{
In: bytes.NewReader(randomData),
Out: &stdout,
Raw: true,
TryDev: true,
}

roundTripper, err := spdy.NewRoundTripperWithConfig(spdy.RoundTripperConfig{
TLS: http.DefaultTransport.(*http.Transport).TLSClientConfig,
Proxier: http.ProxyFromEnvironment,
PingPeriod: 5 * time.Second,
})
if err != nil {
return err
}
exec, err := remotecommand.NewSPDYExecutorForTransports(roundTripper, roundTripper, http.MethodGet, execUrl)
if err != nil {
return err
}

return tty.Safe(func() error {
return exec.StreamWithContext(ctx, remotecommand.StreamOptions{
Stdin: tty.In,
Stdout: tty.Out,
Tty: true,
})
})
}
3 changes: 2 additions & 1 deletion provider/server/server_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const (
consistentlyDuration = 1 * time.Second
machineClassx3xlarge = "x3-xlarge"
machineClassx2medium = "x2-medium"
baseURL = "http://localhost:8080"
baseURL = "http://localhost:20251"
streamingAddress = "127.0.0.1:20251"
)

Expand Down Expand Up @@ -110,6 +110,7 @@ var _ = BeforeSuite(func() {
GCVMGracefulShutdownTimeout: 10 * time.Second,
ResyncIntervalGarbageCollector: 5 * time.Second,
ResyncIntervalVolumeSize: 1 * time.Minute,
VirshExecutable: "virsh",
}

srvCtx, cancel := context.WithCancel(context.Background())
Expand Down

0 comments on commit f65182b

Please sign in to comment.