diff --git a/benchmark-agent/.gitignore b/benchmark-agent/.gitignore index 5a35498..183c91c 100644 --- a/benchmark-agent/.gitignore +++ b/benchmark-agent/.gitignore @@ -1 +1,17 @@ -benchmark-agent \ No newline at end of file +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ + +# Others +benchmark-agent diff --git a/benchmark-agent/agent.go b/benchmark-agent/agent.go deleted file mode 100644 index a3a5848..0000000 --- a/benchmark-agent/agent.go +++ /dev/null @@ -1,272 +0,0 @@ -package main - -import ( - "net/http" - "strconv" - "strings" - "sync" - - "github.com/fsouza/go-dockerclient" - "github.com/gin-gonic/gin" - "github.com/golang/glog" - "github.com/hyperpilotio/container-benchmarks/benchmark-agent/apis" -) - -type Server struct { - dockerClient *docker.Client - Port string - mutex *sync.Mutex - Benchmarks map[string]*DeployedBenchmark -} - -type DeployedBenchmark struct { - Benchmark *apis.Benchmark - NameToId map[string]string -} - -func NewServer(client *docker.Client, port string) *Server { - return &Server{ - dockerClient: client, - Port: port, - mutex: &sync.Mutex{}, - Benchmarks: make(map[string]*DeployedBenchmark), - } -} - -func (server *Server) removeContainers(prefix string) { - // TODO: add code to remove existing containers with names matching the prefix -} - -func (server *Server) deployBenchmark(benchmark *apis.Benchmark) (*DeployedBenchmark, error) { - hostConfig := &docker.HostConfig{ - PublishAllPorts: true, - } - - deployed := &DeployedBenchmark{ - Benchmark: benchmark, - NameToId: make(map[string]string), - } - - glog.Infof("Deploying new benchmark: %v", benchmark) - - parts := strings.Split(benchmark.Image, ":") - image := parts[0] - tag := "latest" - if len(parts) > 1 { - tag = parts[1] - } - // TODO: we may not need to re-pull the image for every new benchmark posted - glog.Infof("Pulling image %s:%s for benchmark %s", image, tag, benchmark.Name) - err := server.dockerClient.PullImage(docker.PullImageOptions{ - Repository: image, - Tag: tag, - }, docker.AuthConfiguration{}) - - if err != nil { - glog.Errorf("Unable to pull image %s:%s for benchmark %s", image, tag, benchmark.Name) - return nil, err - } - - config := &docker.Config{ - Image: benchmark.Image, - } - - config.Cmd = append(config.Cmd, benchmark.Command.Path) - for _, arg := range benchmark.Command.Args { - config.Cmd = append(config.Cmd, arg) - } - - hostConfig.CPUPeriod = 100000 // default CpuPeriod value - cgroup := &benchmark.CgroupConfig - if cgroup != nil && cgroup.SetCpuQuota { // use cgroup cpu quota to control benchmark intensity - hostConfig.CPUQuota = hostConfig.CPUPeriod * benchmark.Intensity / 100 - } else { // pass intensity value directly into benchmark command - config.Cmd = append(config.Cmd, strconv.Itoa(int(benchmark.Intensity))) - } - - containerCount := 1 - if benchmark.Count > 0 { - containerCount = benchmark.Count - } - - for i := 1; i <= containerCount; i++ { - containerName := benchmark.Name + strconv.Itoa(i) - container, err := server.dockerClient.CreateContainer(docker.CreateContainerOptions{ - Name: containerName, - Config: config, - HostConfig: hostConfig, - }) - - if err != nil { - glog.Errorf("Unable to create container for benchmark %s", benchmark.Name) - // Clean up - server.removeContainers(benchmark.Name) - return nil, err - } - - deployed.NameToId[containerName] = container.ID - - err = server.dockerClient.StartContainer(container.ID, hostConfig) - if err != nil { - glog.Errorf("Unable to start container for benchmark %s", benchmark.Name) - // Clean up - server.removeContainers(benchmark.Name) - return nil, err - } - } - - glog.Infof("Successfully deployed containers for benchmark %s", benchmark.Name) - - return deployed, nil -} - -func (server *Server) createBenchmark(c *gin.Context) { - var benchmark apis.Benchmark - if err := c.BindJSON(&benchmark); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": true, - "data": "Error deserializing benchmark: " + string(err.Error()), - }) - return - } - - server.mutex.Lock() - defer server.mutex.Unlock() - if _, ok := server.Benchmarks[benchmark.Name]; ok { - c.JSON(http.StatusBadRequest, gin.H{ - "error": true, - "data": "Benchmark " + benchmark.Name + " already created. Please delete it before re-creating", - }) - return - } - - deployed, err := server.deployBenchmark(&benchmark) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": true, - "data": "Failed to deploy benchmark " + benchmark.Name + ": " + string(err.Error()), - }) - return - } - - server.Benchmarks[benchmark.Name] = deployed - c.JSON(http.StatusAccepted, gin.H{ - "error": false, - }) -} - -func (server *Server) deleteBenchmark(c *gin.Context) { - benchmarkName := c.Param("benchmark") - server.mutex.Lock() - defer server.mutex.Unlock() - - deployed, ok := server.Benchmarks[benchmarkName] - if !ok { - c.JSON(http.StatusNotFound, gin.H{ - "error": false, - }) - return - } - - for i := 1; i <= deployed.Benchmark.Count; i++ { - err := server.dockerClient.RemoveContainer(docker.RemoveContainerOptions{ - ID: deployed.NameToId[deployed.Benchmark.Name+strconv.Itoa(i)], - Force: true, - RemoveVolumes: true, - }) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": true, - "data": "Unable to remove container: " + err.Error(), - }) - return - } - } - - delete(server.Benchmarks, deployed.Benchmark.Name) - - c.JSON(http.StatusAccepted, gin.H{ - "error": false, - }) -} - -func (server *Server) updateIntensity(c *gin.Context) { - benchmarkName := c.Param("benchmark") - server.mutex.Lock() - defer server.mutex.Unlock() - glog.Infof("Updating resource intensity for benchmark %v", benchmarkName) - - /* - deployed, ok := server.Benchmarks[benchmarkName] - if !ok { - c.JSON(http.StatusNotFound, gin.H{ - "error": false, - }) - return - } - updateOptions := docker.UpdateContainerOptions{} - if resources.CPUShares > 0 { - updateOptions.CPUShares = int(resources.CPUShares) - } - - if resources.Memory > 0 { - updateOptions.Memory = int(resources.Memory) - } - - glog.Infof("Updating resources for benchmark", deployed.Benchmark.Name) - for i := 1; i <= deployed.Benchmark.Count; i++ { - containerId := deployed.NameToId[deployed.Benchmark.Name+strconv.Itoa(i)] - glog.Infof("Updating container ID %s, %+v", containerId, updateOptions) - err := server.dockerClient.UpdateContainer(containerId, updateOptions) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": true, - "data": "Unable to update resources: " + err.Error(), - }) - return - } - } - */ - - c.JSON(http.StatusAccepted, gin.H{ - "error": false, - }) -} - -func (server *Server) Run() error { - //gin.SetMode("release") - router := gin.New() - - // Global middleware - router.Use(gin.Logger()) - router.Use(gin.Recovery()) - - benchmarkGroup := router.Group("/benchmarks") - { - benchmarkGroup.POST("", server.createBenchmark) - benchmarkGroup.DELETE("/:benchmark", server.deleteBenchmark) - benchmarkGroup.PUT("/:benchmark/intensity", server.updateIntensity) - } - - return router.Run(":" + server.Port) -} - -func main() { - endpoint := "unix:///var/run/docker.sock" - client, err := docker.NewClient(endpoint) - if err != nil { - panic(err) - } - - err = client.Ping() - if err != nil { - glog.Error("Unable to ping docker daemon") - panic(err) - } - - server := NewServer(client, "7778") - err = server.Run() - if err != nil { - panic(err) - } -} diff --git a/benchmark-agent/api.go b/benchmark-agent/api.go new file mode 100644 index 0000000..11ec214 --- /dev/null +++ b/benchmark-agent/api.go @@ -0,0 +1,144 @@ +package main + +import ( + "fmt" + "net/http" + "time" + + logger "github.com/Sirupsen/logrus" + "github.com/gin-contrib/cors" + "github.com/gin-gonic/gin" + "github.com/hyperpilotio/container-benchmarks/benchmark-agent/model" +) + +var corsConfig cors.Config + +func init() { + headers := []string{ + "Content-Type", "Content-Length", "Accept-Encoding", "X-CSRF-Token", "Authorization", "Cache-Control", "X-Requested-With", + "accept", "origin", "Apitoken", + "page-size", "page-pos", "order-by", "page-ptr", "total-count", "page-more", "previous-page", "next-page", + } + + corsConfig = cors.Config{ + AllowMethods: []string{"POST", "OPTIONS", "GET", "PUT", "DELETE", "UPDATE"}, + AllowHeaders: headers, + ExposeHeaders: headers, + AllowCredentials: true, + MaxAge: 12 * time.Hour, + } + corsConfig.AllowAllOrigins = true +} + +type httpServConfig struct { + Mode string + Host string + Port uint16 +} + +func (c *httpServConfig) String() string { + return fmt.Sprintf("%s:%d", c.Host, c.Port) +} + +func initHTTPServ() { + initGin(&httpServConfig{ + Mode: "debug", + Host: "0.0.0.0", + Port: 7778, + }) +} + +func setAPIRoutes(router *gin.Engine) { + router.POST("benchmarks", createBenchmark) + router.DELETE("benchmarks/:benchmark", deleteBenchmark) + router.PUT("benchmarks/:benchmark/intensity", updateIntensity) +} + +func createBenchmark(c *gin.Context) { + var benchmark model.Benchmark + if err := c.BindJSON(&benchmark); err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "error": true, + "data": "Error deserializing benchmark: " + string(err.Error()), + }) + return + } + + if dockerClient.IsCreated(benchmark.Name) { + c.JSON(http.StatusBadRequest, gin.H{ + "error": true, + "data": "Benchmark " + benchmark.Name + " already created. Please delete it before re-creating", + }) + return + } + + if err := dockerClient.DeployBenchmark(&benchmark); err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "error": true, + "data": "Failed to deploy benchmark " + benchmark.Name + ": " + string(err.Error()), + }) + return + } + + c.JSON(http.StatusAccepted, gin.H{ + "error": false, + }) +} + +func deleteBenchmark(c *gin.Context) { + name := c.Param("benchmark") + depBenchmark := dockerClient.DeployedBenchmark(name) + if depBenchmark == nil { + c.JSON(http.StatusNotFound, gin.H{ + "error": false, + }) + return + } + + if err := dockerClient.RemoveDeployedBenchmark(depBenchmark); err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "error": true, + "data": "Unable to remove container: " + err.Error(), + }) + return + } + + c.JSON(http.StatusAccepted, gin.H{ + "error": false, + }) +} + +func updateIntensity(c *gin.Context) { + name := c.Param("benchmark") + /* + resources := &model.Resources{} + if err := c.BindJSON(resources); err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "error": true, + "data": "Unable to deserialize resources: " + err.Error(), + }) + return + } + */ + + logger.Infof("Updating resource intensity for benchmark %v", name) + depBenchmark := dockerClient.DeployedBenchmark(name) + if depBenchmark == nil { + c.JSON(http.StatusNotFound, gin.H{ + "error": false, + }) + return + } + /* + if err := dockerClient.UpdateResources(depBenchmark, resources); err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "error": true, + "data": "Unable to update resources: " + err.Error(), + }) + return + } + */ + c.JSON(http.StatusAccepted, gin.H{ + "error": false, + }) +} diff --git a/benchmark-agent/docker.go b/benchmark-agent/docker.go new file mode 100644 index 0000000..adecfb7 --- /dev/null +++ b/benchmark-agent/docker.go @@ -0,0 +1,11 @@ +package main + +import ( + "github.com/hyperpilotio/container-benchmarks/benchmark-agent/docker" +) + +var dockerClient *docker.Client + +func initDocker() { + dockerClient = docker.NewClient() +} diff --git a/benchmark-agent/docker/docker.go b/benchmark-agent/docker/docker.go new file mode 100644 index 0000000..6da5bcd --- /dev/null +++ b/benchmark-agent/docker/docker.go @@ -0,0 +1,183 @@ +package docker + +import ( + "strconv" + "strings" + "sync" + + logger "github.com/Sirupsen/logrus" + docker "github.com/fsouza/go-dockerclient" + "github.com/hyperpilotio/container-benchmarks/benchmark-agent/model" +) + +type Client struct { + c *docker.Client + benchmarks map[string]*DeployedBenchmark + mutex sync.RWMutex +} + +type DeployedBenchmark struct { + benchmark *model.Benchmark + nameToID map[string]string +} + +func NewClient() *Client { + endpoint := "unix:///var/run/docker.sock" + c, err := docker.NewClient(endpoint) + if err != nil { + panic(err) + } + + err = c.Ping() + if err != nil { + logger.Errorln("Unable to ping docker daemon") + panic(err) + } + + return &Client{c: c, benchmarks: make(map[string]*DeployedBenchmark)} +} + +func (client *Client) IsCreated(name string) bool { + client.mutex.RLock() + defer client.mutex.RUnlock() + if _, ok := client.benchmarks[name]; ok { + return true + } + return false +} + +func (client *Client) DeployedBenchmark(name string) *DeployedBenchmark { + client.mutex.RLock() + defer client.mutex.RUnlock() + if v, ok := client.benchmarks[name]; ok { + return v + } + return nil +} + +func (client *Client) DeployBenchmark(benchmark *model.Benchmark) error { + hostConfig := &docker.HostConfig{ + PublishAllPorts: true, + } + + deployed := &DeployedBenchmark{ + benchmark: benchmark, + nameToID: make(map[string]string), + } + + logger.Infof("Deploying new benchmark: %v", benchmark) + + parts := strings.Split(benchmark.Image, ":") + image := parts[0] + tag := "latest" + if len(parts) > 1 { + tag = parts[1] + } + + // TODO: we may not need to re-pull the image for every new benchmark posted + logger.Infof("Pulling image %s:%s for benchmark %s", image, tag, benchmark.Name) + if err := client.c.PullImage(docker.PullImageOptions{ + Repository: image, + Tag: tag, + }, + docker.AuthConfiguration{}, + ); err != nil { + logger.Errorf("Unable to pull image %s:%s for benchmark %s", image, tag, benchmark.Name) + return err + } + + config := &docker.Config{ + Image: benchmark.Image, + } + + config.Cmd = append(config.Cmd, benchmark.Command.Path) + for _, arg := range benchmark.Command.Args { + config.Cmd = append(config.Cmd, arg) + } + + hostConfig.CPUPeriod = 100000 // default CpuPeriod value + cgroup := &benchmark.CgroupConfig + if cgroup != nil && cgroup.SetCpuQuota { // use cgroup cpu quota to control benchmark intensity + hostConfig.CPUQuota = hostConfig.CPUPeriod * benchmark.Intensity / 100 + } else { // pass intensity value directly into benchmark command + config.Cmd = append(config.Cmd, strconv.Itoa(int(benchmark.Intensity))) + } + + containerCount := 1 + if benchmark.Count > 0 { + containerCount = benchmark.Count + } + + for i := 1; i <= containerCount; i++ { + containerName := benchmark.Name + strconv.Itoa(i) + container, err := client.c.CreateContainer(docker.CreateContainerOptions{ + Name: containerName, + Config: config, + HostConfig: hostConfig, + }) + if err != nil { + logger.Errorf("Unable to create container for benchmark %s", benchmark.Name) + // Clean up + client.removeContainers(benchmark.Name) + return err + } + + deployed.nameToID[containerName] = container.ID + + err = client.c.StartContainer(container.ID, hostConfig) + if err != nil { + logger.Errorf("Unable to start container for benchmark %s", benchmark.Name) + // Clean up + client.removeContainers(benchmark.Name) + return err + } + } + + logger.Infof("Successfully deployed containers for benchmark %s", benchmark.Name) + client.mutex.Lock() + defer client.mutex.Unlock() + client.benchmarks[benchmark.Name] = deployed + return nil +} + +func (client *Client) removeContainers(prefix string) { + // TODO: add code to remove existing containers with names matching the prefix +} + +func (client *Client) RemoveDeployedBenchmark(b *DeployedBenchmark) error { + for _, id := range b.nameToID { + if err := client.c.RemoveContainer(docker.RemoveContainerOptions{ + ID: id, + Force: true, + RemoveVolumes: true, + }); err != nil { + return err + } + } + client.mutex.Lock() + defer client.mutex.Unlock() + delete(client.benchmarks, b.benchmark.Name) + return nil +} + +/* +func (client *Client) UpdateResources(b *DeployedBenchmark, r *model.Resources) error { + updateOptions := docker.UpdateContainerOptions{} + if r.CPUShares > 0 { + updateOptions.CPUShares = int(r.CPUShares) + } + + if r.Memory > 0 { + updateOptions.Memory = int(r.Memory) + } + + logger.Infoln("Updating resources for benchmark", b.benchmark.Name) + for _, id := range b.nameToID { + logger.Infoln("Updating container ID %s, %+v", id, updateOptions) + if err := client.c.UpdateContainer(id, updateOptions); err != nil { + return err + } + } + return nil +} +*/ diff --git a/benchmark-agent/gin.go b/benchmark-agent/gin.go new file mode 100644 index 0000000..65d1d15 --- /dev/null +++ b/benchmark-agent/gin.go @@ -0,0 +1,32 @@ +package main + +import ( + logger "github.com/Sirupsen/logrus" + "github.com/gin-contrib/cors" + "github.com/gin-gonic/gin" +) + +func initGin(c *httpServConfig) { + router := NewDefaultJsonEngine(c) + logger.Infof("Going to start web service. Listen: %s", c) + mustStartAPIService(router, c) +} + +func mustStartAPIService(router *gin.Engine, c *httpServConfig) { + setAPIRoutes(router) + if err := router.Run(c.String()); err != nil { + logger.Panicf("Cannot start web service: %v", err) + } +} + +func NewDefaultJsonEngine(c *httpServConfig) *gin.Engine { + gin.SetMode(c.Mode) + + router := gin.New() + + router.Use(cors.New(corsConfig)) + router.Use(gin.Logger()) + router.Use(gin.Recovery()) + + return router +} diff --git a/benchmark-agent/it_test.go b/benchmark-agent/it_test.go new file mode 100644 index 0000000..c89b968 --- /dev/null +++ b/benchmark-agent/it_test.go @@ -0,0 +1,115 @@ +package main + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/hyperpilotio/container-benchmarks/benchmark-agent/model" + testHttp "github.com/hyperpilotio/container-benchmarks/benchmark-agent/test/http" +) + +func TestByGinkgo(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Base Suite") +} + +var httpClientConfig = testHttp.NewClientConfig() + +var _ = Describe("Test creating benchmarks", func() { + AfterEach(func() { + testHttp.Response( + httpClientConfig.NewSling(). + Delete("benchmarks/busycpu"), + ) + }) + + It("creates benchmarks", func() { + req := &model.Benchmark{ + Name: "busycpu", + Count: 4, + Resources: &model.Resources{ + CPUShares: 512, + }, + Image: "hyperpilot/busycpu", + Intensity: 100, + } + resp := testHttp.Response( + httpClientConfig.NewSling(). + Post("benchmarks"). + BodyJSON(req), + ) + + jsonBody := resp.JSONBody() + Expect(jsonBody.Get("error").MustBool()).To(BeFalse()) + }) +}) + +var _ = Describe("Test updating benchmarks", func() { + BeforeEach(func() { + req := &model.Benchmark{ + Name: "busycpu", + Count: 4, + Resources: &model.Resources{ + CPUShares: 512, + }, + Image: "hyperpilot/busycpu", + Intensity: 100, + } + testHttp.Response( + httpClientConfig.NewSling(). + Post("benchmarks"). + BodyJSON(req), + ) + }) + + AfterEach(func() { + testHttp.Response( + httpClientConfig.NewSling(). + Delete("benchmarks/busycpu"), + ) + }) + + It("updates benchmarks", func() { + req := &model.Resources{ + CPUShares: 256, + } + resp := testHttp.Response( + httpClientConfig.NewSling(). + Post("benchmarks/busycpu/resources"). + BodyJSON(req), + ) + + jsonBody := resp.JSONBody() + Expect(jsonBody.Get("error").MustBool()).To(BeFalse()) + }) +}) + +var _ = Describe("Test deleting benchmarks", func() { + BeforeEach(func() { + req := &model.Benchmark{ + Name: "busycpu", + Count: 4, + Resources: &model.Resources{ + CPUShares: 512, + }, + Image: "hyperpilot/busycpu", + Intensity: 100, + } + testHttp.Response( + httpClientConfig.NewSling(). + Post("benchmarks"). + BodyJSON(req), + ) + }) + + It("deletes benchmarks", func() { + resp := testHttp.Response( + httpClientConfig.NewSling(). + Delete("benchmarks/busycpu"), + ) + jsonBody := resp.JSONBody() + Expect(jsonBody.Get("error").MustBool()).To(BeFalse()) + }) +}) diff --git a/benchmark-agent/main.go b/benchmark-agent/main.go new file mode 100644 index 0000000..0298e58 --- /dev/null +++ b/benchmark-agent/main.go @@ -0,0 +1,6 @@ +package main + +func main() { + initDocker() + initHTTPServ() +} diff --git a/benchmark-agent/apis/models.go b/benchmark-agent/model/model.go similarity index 97% rename from benchmark-agent/apis/models.go rename to benchmark-agent/model/model.go index eaf4b52..04c4cec 100644 --- a/benchmark-agent/apis/models.go +++ b/benchmark-agent/model/model.go @@ -1,4 +1,4 @@ -package apis +package model type CgroupConfig struct { SetCpuQuota bool `json:"setCpuQuota"` diff --git a/benchmark-agent/test/http/http.go b/benchmark-agent/test/http/http.go new file mode 100644 index 0000000..9544a09 --- /dev/null +++ b/benchmark-agent/test/http/http.go @@ -0,0 +1,146 @@ +package http + +import ( + "flag" + "fmt" + "io/ioutil" + "net/http" + + log "github.com/Sirupsen/logrus" + simplejson "github.com/bitly/go-simplejson" + "github.com/dghubble/sling" +) + +// Response sends the HTTP request and reads the body of the HTTP response +func Response(s *sling.Sling) *ResponseExt { + /** + * Set up the HTTP request + */ + req, err := s.Request() + if err != nil { + panic(err) + } + // :~) + + return responseExtByRequest(req) +} + +func responseExtByRequest(req *http.Request) *ResponseExt { + /** + * Send the HTTP request + */ + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + panic(err) + } + // :~) + + return responseExtByResponse(resp) +} + +func responseExtByResponse(resp *http.Response) *ResponseExt { + /** + * Read the body of the HTTP response + */ + defer resp.Body.Close() + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + panic(err) + } + // :~) + + return &ResponseExt{ + Response: resp, + body: bodyBytes, + } +} + +// ResponseExt is an extended type of `http.Response` +type ResponseExt struct { + Response *http.Response + body []byte +} + +// JSONBody returns the body of the HTTP response in JSON format. It panics if +// any error occurs during the parsing. +func (r *ResponseExt) JSONBody() *simplejson.Json { + jsonResult, err := simplejson.NewJson(r.body) + if err != nil { + panic(err) + } + + return jsonResult +} + +// ClientConfig is the configuration of the http client +type ClientConfig struct { + Ssl bool // host of the http service + Host string // port of the http service + Port uint16 // enable SSL for the http service + Resource string // specify the resource, i.e. `http://:/` + + slingBase *sling.Sling +} + +// NewClientConfig returns a new ClientConfig. The values of the fields +// can be set by the command line: +// Ssl: by `-http.host` +// Host: by `-http.port` +// Port: by `-http.ssl` +// Resource: by `-http.resource` +func NewClientConfig() *ClientConfig { + return newClientConfigByFlag() +} + +func newClientConfigByFlag() *ClientConfig { + var host = flag.String("http.host", "127.0.0.1", "Host of the tested HTTP service") + var port = flag.Int("http.port", 7778, "Port of the tested HTTP service") + var ssl = flag.Bool("http.ssl", false, "Enable SSL for the tested HTTP service") + var resource = flag.String("http.resource", "", "specify the resource, i.e. 'http://:/'") + + flag.Parse() + + config := &ClientConfig{ + Host: *host, + Port: uint16(*port), + Ssl: *ssl, + Resource: *resource, + } + config.slingBase = sling.New().Base( + config.hostAndPort(), + ) + + if config.Resource != "" { + config.slingBase.Path(config.Resource + "/") + } + + log.Infof("Sling URL for testing: %s", config.String()) + + return config +} + +func (c *ClientConfig) hostAndPort() string { + schema := "http" + if c.Ssl { + schema = "https" + } + + return fmt.Sprintf("%s://%s:%d", schema, c.Host, c.Port) +} + +// String gets the URL string the client accesses to +func (c *ClientConfig) String() string { + url := c.hostAndPort() + + if c.Resource != "" { + url += "/" + c.Resource + } + + return url +} + +// NewSling returns a new `Sling` variable based on the `ClientConfig`. +func (c *ClientConfig) NewSling() *sling.Sling { + return c.slingBase.New() +} diff --git a/benchmark-agent/update-example.json b/benchmark-agent/update-example.json deleted file mode 100644 index ed4a331..0000000 --- a/benchmark-agent/update-example.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "cpushares": 256 -}