summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@gmail.com>2021-08-25 08:06:14 +0200
committerJon Bratseth <bratseth@gmail.com>2021-08-25 08:06:14 +0200
commit3b1eca74dce4aea412425606c53680eecb780f13 (patch)
treea2bc18a5bc4a5a648f6fdd23835c8b4fe9353673 /client
parentf4e1ac3c1ea67bf1599838764988cf3ad2aa8357 (diff)
Separate activate and prepare top level commands
Diffstat (limited to 'client')
-rw-r--r--client/go/cmd/activate.go25
-rw-r--r--client/go/cmd/deploy.go174
-rw-r--r--client/go/cmd/deploy_test.go12
-rw-r--r--client/go/cmd/document.go2
-rw-r--r--client/go/cmd/prepare.go29
-rw-r--r--client/go/cmd/query.go2
-rw-r--r--client/go/cmd/status.go8
-rw-r--r--client/go/cmd/target.go12
-rw-r--r--client/go/vespa/deploy.go137
9 files changed, 221 insertions, 180 deletions
diff --git a/client/go/cmd/activate.go b/client/go/cmd/activate.go
new file mode 100644
index 00000000000..fe989726253
--- /dev/null
+++ b/client/go/cmd/activate.go
@@ -0,0 +1,25 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// vespa activate command
+// Author: bratseth
+
+package cmd
+
+import (
+ "github.com/spf13/cobra"
+ "github.com/vespa-engine/vespa/vespa"
+)
+
+func init() {
+ rootCmd.AddCommand(activateCmd)
+}
+
+// TODO: Implement and test
+
+var activateCmd = &cobra.Command{
+ Use: "activate",
+ Short: "Activates (deploys) the previously prepared application package",
+ Long: `TODO`,
+ Run: func(cmd *cobra.Command, args []string) {
+ vespa.Deploy(true, "", deployTarget())
+ },
+}
diff --git a/client/go/cmd/deploy.go b/client/go/cmd/deploy.go
index bfd3837cd5a..0b0cd55abf9 100644
--- a/client/go/cmd/deploy.go
+++ b/client/go/cmd/deploy.go
@@ -5,187 +5,23 @@
package cmd
import (
- "archive/zip"
- "errors"
"github.com/spf13/cobra"
- "github.com/vespa-engine/vespa/util"
- "io"
- "io/ioutil"
- "net/http"
- "net/url"
- "os"
- "path/filepath"
- "strings"
- "time"
+ "github.com/vespa-engine/vespa/vespa"
)
func init() {
rootCmd.AddCommand(deployCmd)
- deployCmd.AddCommand(deployPrepareCmd)
- deployCmd.AddCommand(deployActivateCmd)
}
var deployCmd = &cobra.Command{
Use: "deploy",
- Short: "Deploys an application package",
- Long: `TODO: Use prepare or deploy activate`,
- Run: func(cmd *cobra.Command, args []string) {
- util.Error("Use either deploy prepare or deploy activate")
- },
-}
-
-var deployPrepareCmd = &cobra.Command{
- Use: "prepare",
- Short: "Prepares an application for activation",
- Long: `TODO: prepare application-package-dir OR application.zip`,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) > 1 {
- return errors.New("Expected an application package as the only argument")
- }
- return nil
- },
+ Short: "Deploys (prepares and activates) an application package",
+ Long: `TODO`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
- deploy(true, "src/main/application")
+ vespa.Deploy(false, "", deployTarget())
} else {
- deploy(true, args[0])
+ vespa.Deploy(false, args[0], deployTarget())
}
},
}
-
-var deployActivateCmd = &cobra.Command{
- Use: "activate",
- Short: "Activates an application package. If no package argument, the previously prepared package is activated.",
- Long: `TODO: activate [application-package-dir OR application.zip]`,
- Args: func(cmd *cobra.Command, args []string) error {
- if len(args) > 1 {
- return errors.New("Expected an application package as the only argument")
- }
- return nil
- },
- Run: func(cmd *cobra.Command, args []string) {
- if len(args) == 0 {
- deploy(false, "")
- } else {
- deploy(false, args[0])
- }
- },
-}
-
-func deploy(prepare bool, application string) {
- // TODO: Support no application (activate)
- // TODO: Support application home as argument instead of src/main and
- // - if target exists, use target/application.zip
- // - else if src/main/application exists, use that
- // - else if current dir has services.xml use that
- if filepath.Ext(application) != ".zip" {
- tempZip, error := ioutil.TempFile("", "application.zip")
- if error != nil {
- util.Error("Could not create a temporary zip file for the application package")
- util.Detail(error.Error())
- return
- }
-
- error = zipDir(application, tempZip.Name())
- if (error != nil) {
- util.Error(error.Error())
- return
- }
- defer os.Remove(tempZip.Name())
- application = tempZip.Name()
- }
-
- zipFileReader, zipFileError := os.Open(application)
- if zipFileError != nil {
- util.Error("Could not open application package at " + application)
- util.Detail(zipFileError.Error())
- return
- }
-
- var deployUrl *url.URL
- if prepare {
- deployUrl, _ = url.Parse(getTarget(deployContext).deploy + "/application/v2/tenant/default/prepare")
- } else if application == "" {
- deployUrl, _ = url.Parse(getTarget(deployContext).deploy + "/application/v2/tenant/default/activate")
- } else {
- deployUrl, _ = url.Parse(getTarget(deployContext).deploy + "/application/v2/tenant/default/prepareandactivate")
- }
-
- header := http.Header{}
- header.Add("Content-Type", "application/zip")
- request := &http.Request{
- URL: deployUrl,
- Method: "POST",
- Header: header,
- Body: ioutil.NopCloser(zipFileReader),
- }
- serviceDescription := "Deploy service"
- response := util.HttpDo(request, time.Minute * 10, serviceDescription)
- if (response == nil) {
- return
- }
-
- defer response.Body.Close()
- if response.StatusCode == 200 {
- util.Success("Success")
- } else if response.StatusCode / 100 == 4 {
- util.Error("Invalid application package", "(" + response.Status + "):")
- util.PrintReader(response.Body)
- } else {
- util.Error("Error from", strings.ToLower(serviceDescription), "at", request.URL.Host, "(" + response.Status + "):")
- util.PrintReader(response.Body)
- }
-}
-
-func zipDir(dir string, destination string) error {
- if filepath.IsAbs(dir) {
- message := "Path must be relative, but '" + dir + "'"
- return errors.New(message)
- }
- if ! util.PathExists(dir) {
- message := "'" + dir + "' should be an application package zip or dir, but does not exist"
- return errors.New(message)
- }
- if ! util.IsDirectory(dir) {
- message := "'" + dir + "' should be an application package dir, but is a (non-zip) file"
- return errors.New(message)
- }
-
- file, err := os.Create(destination)
- if err != nil {
- message := "Could not create a temporary zip file for the application package: " + err.Error()
- return errors.New(message)
- }
- defer file.Close()
-
- w := zip.NewWriter(file)
- defer w.Close()
-
- walker := func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if info.IsDir() {
- return nil
- }
- file, err := os.Open(path)
- if err != nil {
- return err
- }
- defer file.Close()
-
- zippath := strings.TrimPrefix(path, dir)
- zipfile, err := w.Create(zippath)
- if err != nil {
- return err
- }
-
- _, err = io.Copy(zipfile, file)
- if err != nil {
- return err
- }
- return nil
- }
- return filepath.Walk(dir, walker)
-}
-
diff --git a/client/go/cmd/deploy_test.go b/client/go/cmd/deploy_test.go
index 64ede50546c..c80b18d0878 100644
--- a/client/go/cmd/deploy_test.go
+++ b/client/go/cmd/deploy_test.go
@@ -14,7 +14,7 @@ func TestDeployZip(t *testing.T) {
client := &mockHttpClient{}
assert.Equal(t,
"\x1b[32mSuccess\n",
- executeCommand(t, client, []string{"deploy", "activate", "testdata/application.zip"}, []string{}))
+ executeCommand(t, client, []string{"deploy", "testdata/application.zip"}, []string{}))
assertDeployRequestMade("http://127.0.0.1:19071", client, t)
}
@@ -22,7 +22,7 @@ func TestDeployZipWithURLTargetArgument(t *testing.T) {
client := &mockHttpClient{}
assert.Equal(t,
"\x1b[32mSuccess\n",
- executeCommand(t, client, []string{"deploy", "activate", "testdata/application.zip", "-t", "http://target:19071"}, []string{}))
+ executeCommand(t, client, []string{"deploy", "testdata/application.zip", "-t", "http://target:19071"}, []string{}))
assertDeployRequestMade("http://target:19071", client, t)
}
@@ -30,7 +30,7 @@ func TestDeployZipWitLocalTargetArgument(t *testing.T) {
client := &mockHttpClient{}
assert.Equal(t,
"\x1b[32mSuccess\n",
- executeCommand(t, client, []string{"deploy", "activate", "testdata/application.zip", "-t", "local"}, []string{}))
+ executeCommand(t, client, []string{"deploy", "testdata/application.zip", "-t", "local"}, []string{}))
assertDeployRequestMade("http://127.0.0.1:19071", client, t)
}
@@ -38,7 +38,7 @@ func TestDeployDirectory(t *testing.T) {
client := &mockHttpClient{}
assert.Equal(t,
"\x1b[32mSuccess\n",
- executeCommand(t, client, []string{"deploy", "activate", "testdata/src/main/application"}, []string{}))
+ executeCommand(t, client, []string{"deploy", "testdata/src/main/application"}, []string{}))
assertDeployRequestMade("http://127.0.0.1:19071", client, t)
}
@@ -67,12 +67,12 @@ func assertApplicationPackageError(t *testing.T, status int, errorMessage string
client := &mockHttpClient{ nextStatus: status, nextBody: errorMessage, }
assert.Equal(t,
"\x1b[31mInvalid application package (Status " + strconv.Itoa(status) + "):\n" + errorMessage + "\n",
- executeCommand(t, client, []string{"deploy", "activate", "testdata/src/main/application"}, []string{}))
+ executeCommand(t, client, []string{"deploy", "testdata/src/main/application"}, []string{}))
}
func assertDeployServerError(t *testing.T, status int, errorMessage string) {
client := &mockHttpClient{ nextStatus: status, nextBody: errorMessage, }
assert.Equal(t,
"\x1b[31mError from deploy service at 127.0.0.1:19071 (Status " + strconv.Itoa(status) + "):\n" + errorMessage + "\n",
- executeCommand(t, client, []string{"deploy", "activate", "testdata/src/main/application"}, []string{}))
+ executeCommand(t, client, []string{"deploy", "testdata/src/main/application"}, []string{}))
}
diff --git a/client/go/cmd/document.go b/client/go/cmd/document.go
index 1d3cb2feb58..9e51f3c8857 100644
--- a/client/go/cmd/document.go
+++ b/client/go/cmd/document.go
@@ -87,7 +87,7 @@ func post(documentId string, jsonFile string) {
}
}
- url, _ := url.Parse(getTarget(documentContext).document + "/document/v1/" + documentId)
+ url, _ := url.Parse(documentTarget() + "/document/v1/" + documentId)
request := &http.Request{
URL: url,
diff --git a/client/go/cmd/prepare.go b/client/go/cmd/prepare.go
new file mode 100644
index 00000000000..b65f845be81
--- /dev/null
+++ b/client/go/cmd/prepare.go
@@ -0,0 +1,29 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// vespa prepare command
+// Author: bratseth
+
+package cmd
+
+import (
+ "github.com/spf13/cobra"
+ "github.com/vespa-engine/vespa/vespa"
+)
+
+func init() {
+ rootCmd.AddCommand(prepareCmd)
+}
+
+// TODO: Implement and test
+
+var prepareCmd = &cobra.Command{
+ Use: "prepare",
+ Short: "Prepares an application package for activation",
+ Long: `TODO`,
+ Run: func(cmd *cobra.Command, args []string) {
+ if len(args) == 0 {
+ vespa.Deploy(true, "", deployTarget())
+ } else {
+ vespa.Deploy(true, args[0], deployTarget())
+ }
+ },
+}
diff --git a/client/go/cmd/query.go b/client/go/cmd/query.go
index 58828dbb7cf..ed412d4a396 100644
--- a/client/go/cmd/query.go
+++ b/client/go/cmd/query.go
@@ -35,7 +35,7 @@ var queryCmd = &cobra.Command{
}
func query(arguments []string) {
- url, _ := url.Parse(getTarget(queryContext).query + "/search/")
+ url, _ := url.Parse(queryTarget() + "/search/")
urlQuery := url.Query()
for i := 0; i < len(arguments); i++ {
key, value := splitArg(arguments[i])
diff --git a/client/go/cmd/status.go b/client/go/cmd/status.go
index a011678be09..4187c34c2b1 100644
--- a/client/go/cmd/status.go
+++ b/client/go/cmd/status.go
@@ -15,12 +15,14 @@ func init() {
statusCmd.AddCommand(statusConfigServerCmd)
}
+// TODO: Use deploy, query and document instead of container and config-server
+
var statusCmd = &cobra.Command{
Use: "status",
Short: "Verifies that a vespa target is ready to use (container by default)",
Long: `TODO`,
Run: func(cmd *cobra.Command, args []string) {
- status(getTarget(queryContext).query, "Container")
+ status(queryTarget(), "Container")
},
}
@@ -29,7 +31,7 @@ var statusContainerCmd = &cobra.Command{
Short: "Verifies that your Vespa container endpoint is ready [Default]",
Long: `TODO`,
Run: func(cmd *cobra.Command, args []string) {
- status(getTarget(queryContext).query, "Container")
+ status(queryTarget(), "Container")
},
}
@@ -38,7 +40,7 @@ var statusConfigServerCmd = &cobra.Command{
Short: "Verifies that your Vespa config server endpoint is ready",
Long: `TODO`,
Run: func(cmd *cobra.Command, args []string) {
- status(getTarget(deployContext).deploy, "Config server")
+ status(deployTarget(), "Config server")
},
}
diff --git a/client/go/cmd/target.go b/client/go/cmd/target.go
index 4c1ead7f74e..48ce71bba41 100644
--- a/client/go/cmd/target.go
+++ b/client/go/cmd/target.go
@@ -22,6 +22,18 @@ const (
documentContext context = 2
)
+func deployTarget() string {
+ return getTarget(deployContext).deploy
+}
+
+func queryTarget() string {
+ return getTarget(queryContext).query
+}
+
+func documentTarget() string {
+ return getTarget(documentContext).document
+}
+
func getTarget(targetContext context) *target {
if strings.HasPrefix(targetArgument, "http") {
// TODO: Add default ports if missing
diff --git a/client/go/vespa/deploy.go b/client/go/vespa/deploy.go
new file mode 100644
index 00000000000..3dd3fc21993
--- /dev/null
+++ b/client/go/vespa/deploy.go
@@ -0,0 +1,137 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// vespa deploy API
+// Author: bratseth
+
+package vespa
+
+import (
+ "archive/zip"
+ "errors"
+ "github.com/vespa-engine/vespa/util"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+)
+
+func Deploy(prepare bool, application string, target string) {
+ // TODO: Support no application (activate)
+ // TODO: Support application home as argument instead of src/main and
+ // - if target exists, use target/application.zip
+ // - else if src/main/application exists, use that
+ // - else if current dir has services.xml use that
+ if filepath.Ext(application) != ".zip" {
+ tempZip, error := ioutil.TempFile("", "application.zip")
+ if error != nil {
+ util.Error("Could not create a temporary zip file for the application package")
+ util.Detail(error.Error())
+ return
+ }
+
+ error = zipDir(application, tempZip.Name())
+ if (error != nil) {
+ util.Error(error.Error())
+ return
+ }
+ defer os.Remove(tempZip.Name())
+ application = tempZip.Name()
+ }
+
+ zipFileReader, zipFileError := os.Open(application)
+ if zipFileError != nil {
+ util.Error("Could not open application package at " + application)
+ util.Detail(zipFileError.Error())
+ return
+ }
+
+ var deployUrl *url.URL
+ if prepare {
+ deployUrl, _ = url.Parse(target + "/application/v2/tenant/default/prepare")
+ } else if application == "" {
+ deployUrl, _ = url.Parse(target + "/application/v2/tenant/default/activate")
+ } else {
+ deployUrl, _ = url.Parse(target + "/application/v2/tenant/default/prepareandactivate")
+ }
+
+ header := http.Header{}
+ header.Add("Content-Type", "application/zip")
+ request := &http.Request{
+ URL: deployUrl,
+ Method: "POST",
+ Header: header,
+ Body: ioutil.NopCloser(zipFileReader),
+ }
+ serviceDescription := "Deploy service"
+ response := util.HttpDo(request, time.Minute * 10, serviceDescription)
+ if (response == nil) {
+ return
+ }
+
+ defer response.Body.Close()
+ if response.StatusCode == 200 {
+ util.Success("Success")
+ } else if response.StatusCode / 100 == 4 {
+ util.Error("Invalid application package", "(" + response.Status + "):")
+ util.PrintReader(response.Body)
+ } else {
+ util.Error("Error from", strings.ToLower(serviceDescription), "at", request.URL.Host, "(" + response.Status + "):")
+ util.PrintReader(response.Body)
+ }
+}
+
+func zipDir(dir string, destination string) error {
+ if filepath.IsAbs(dir) {
+ message := "Path must be relative, but '" + dir + "'"
+ return errors.New(message)
+ }
+ if ! util.PathExists(dir) {
+ message := "'" + dir + "' should be an application package zip or dir, but does not exist"
+ return errors.New(message)
+ }
+ if ! util.IsDirectory(dir) {
+ message := "'" + dir + "' should be an application package dir, but is a (non-zip) file"
+ return errors.New(message)
+ }
+
+ file, err := os.Create(destination)
+ if err != nil {
+ message := "Could not create a temporary zip file for the application package: " + err.Error()
+ return errors.New(message)
+ }
+ defer file.Close()
+
+ w := zip.NewWriter(file)
+ defer w.Close()
+
+ walker := func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if info.IsDir() {
+ return nil
+ }
+ file, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ zippath := strings.TrimPrefix(path, dir)
+ zipfile, err := w.Create(zippath)
+ if err != nil {
+ return err
+ }
+
+ _, err = io.Copy(zipfile, file)
+ if err != nil {
+ return err
+ }
+ return nil
+ }
+ return filepath.Walk(dir, walker)
+}
+