Skip to content
Permalink
Browse files
Merge branch 'master' into brooklyn-api-convenience-better-error-prop…
…agation

imports conflict
  • Loading branch information
ahgittin committed May 9, 2017
2 parents 23fdb12 + 0243386 commit 0260945ca098cb7efc072579a3f51be19dec4b6f
Show file tree
Hide file tree
Showing 15 changed files with 177 additions and 107 deletions.
@@ -10,8 +10,9 @@ A command line client for [Apache Brooklyn](https://brooklyn.apache.org).
The CLI tool is written in Go and should be obtained and built as a standard Go project.
You will need the following tools to build it:

- Go (version 1.6.1 or higher), with full cross-compiler support (see https://golang.org/dl).
On Mac, if using Homebrew, use "brew install go --with-cc-all"
- Go (version 1.6.1 or higher), with full cross-compiler support:
the standard [binary packages](https://golang.org/dl) include this,
or you can use your favorite package managers (e.g. `brew install go --with-cc-all`).

Optional:
- Maven (used by the Brooklyn build process)
@@ -21,34 +22,61 @@ Optional:

## Workspace Setup

Go is very particular about the layout of a source tree, and the naming of packages. It is therefore important to
get the code from github.com/apache/brooklyn-client/cli and not your own fork. If you want to contribute to the
project, the procedure to follow is still to get the code from github.com/apache/brooklyn-client/cli, and then to add your
own fork as a remote.
Go is very particular about the layout of a source tree and the source repository,
as it relies on this in the naming of packages.

- Ensure your [$GOPATH](http://golang.org/cmd/go/#hdr-GOPATH_environment_variable) is set correctly
to a suitable location for your Go code, for example, simply $HOME/go.
- Get the Brooklyn CLI and dependencies.
If you're familiar with Go and just want to develop the `br` tool itself you may simply work in your usual `GOPATH`,
using `go get github.com/apache/brooklyn-client/cli/br` and adding your own fork as a remote.
If you know `glide` then you probably know what to do and can ignore these instructions;
`br` is built just like any other Go project.

If you're new to Go and you want to work on the CLI alongside non-Go components in Apache Brooklyn,
then the common Go setup -- where code lives under the `GOPATH` -- may be tedious to work with.
A good pattern is to have the requisite `GOPATH` entry linking to the `brooklyn-client` project
elsewhere on disk, so you have just one copy in the usual space and there is no need to touch the `GOPATH` thereafter.
This is the recommended default described by the instructions below.

First ensure that a `GOPATH` is set; this is where Go will store its files.
`~/go` is the default, and `~/.go` is acceptable also. For example:

```bash
export GOPATH=$HOME/go
```

These instructions now assume that you have `brooklyn-client` checked out and are
in the `cli` subdirectory, where this file resides.
Tell Go to use this checked-out project by linking to it under `GOPATH`:

```bash
go get github.com/apache/brooklyn-client/cli/br
rm -rf $GOPATH/src/github.com/apache/brooklyn-client
cd ..
ln -s `pwd` $GOPATH/src/github.com/apache/brooklyn-client
cd cli
```


## Installing Dependencies

The CLI has a small number of dependencies, notably on `urfave/cli`. To manage the version of dependencies, the CLI
code currently uses [Glide](https://github.com/Masterminds/glide). The dependencies are installed to the top level 'vendor' directory.
The CLI has a small number of dependencies, including the popular `urfave/cli`.
To manage the version of dependencies, the CLI
code currently uses [Glide](https://github.com/Masterminds/glide) to fetch
and maintain these:

```bash
go get github.com/Masterminds/glide
cd $GOPATH/src/github.com/apache/brooklyn-client/cli
glide install
$GOPATH/bin/glide install
```


## Compiling the code with Go for development purposes

Just use the regular Go build commands.
Just use the regular Go build commands:

```bash
go build -o target/br ./br
```

The binary is now ready to use in `target/br`.


## Testing
@@ -64,11 +92,11 @@ sh test.sh http://your-brooklyn-host:8081 myuser mypassword

Note, the tests are not yet comprehensive, and contributions are welcome.


## Building the code as part of the Brooklyn build process

For consistency with the other sub-projects of the overall [Brooklyn](https://github.com/apache/brooklyn) build, Maven
is used to perform the build when brooklyn-client is built as one of the sub-modules of Brooklyn. Most of the work is
delegated to the release/build.sh script, which cross-compiles the code for a number of platform-architecture combinations.
is used to perform the build when brooklyn-client is built as one of the sub-modules of Brooklyn, cross-compiling the code for a number of platform-architecture combinations.

Invoke the build script via Maven with one of

@@ -82,23 +110,28 @@ location, the Maven build makes no assumption about the location of the project
`target` directory is used as the GOPATH, and a soft link is created as `target/src/github.com/apache/brooklyn-cli` to
the code in the root directory.

This builds the requested binaries into the "target" directory, each in its own subdirectory with a name that includes
the platform/architecture details, e.g. bin/linux.386/br. The build installs a maven artifact to the maven repository,
This builds the requested binaries into the `target/` directory, each in its own subdirectory with a name that includes
the platform/architecture details, e.g. `bin/linux.386/br`. The build installs a maven artifact to the maven repository,
consisting of a zip file containing all the binaries. This artifact can be referenced in a POM as

```xml
<groupId>org.apache.brooklyn</groupId>
<artifactId>brooklyn-client-cli</artifactId>
<classifier>bin</classifier>
<type>zip</type>
<version>...</version>
<version>0.12.0-SNAPSHOT</version> <!-- BROOKLYN_VERSION -->
```

Most of the work is delegated to the `release/build.sh` script;
it is not normally necessary to use this, but if you need to know more,
try `release/build.sh -h` for more information.


## Running
## Usage

See instructions in the included [Runtime README](release/files/README) file.


----
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
@@ -23,6 +23,14 @@ import (
"fmt"
"github.com/apache/brooklyn-client/cli/models"
"github.com/apache/brooklyn-client/cli/net"
"net/url"
"path/filepath"
"errors"
"os"
"strings"
"archive/zip"
"io/ioutil"
"bytes"
)

func Icon(network *net.Network, itemId string) ([]byte, error) {
@@ -170,24 +178,108 @@ func Locations(network *net.Network) ([]models.CatalogItemSummary, error) {
return catalogLocations, err
}


func ZipResource(resource string) (*bytes.Buffer, error) {
buf := new(bytes.Buffer)
writer := zip.NewWriter(buf)
defer writer.Close()

walkFn := func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}

relativePath, err := filepath.Rel(resource, path)
if err != nil {
return err
}
f, err := writer.Create(relativePath)
if err != nil {
return err
}

fileBytes, err := ioutil.ReadFile(path)
if err != nil {
return err
}

_, err = f.Write(fileBytes)
if err != nil {
return err
}
return nil
}

err := filepath.Walk(resource, walkFn)

return buf, err;
}

func AddCatalog(network *net.Network, resource string) (map[string]models.CatalogEntitySummary, error) {
url := "/v1/catalog"
urlString := "/v1/catalog"
var entities map[string]models.CatalogEntitySummary
body, err := network.SendPostResourceRequest(url, resource, "application/json")

//Force auto-detect by default
contentType := "application/octet-stream"
u, err := url.Parse(resource)
if err != nil {
return nil, err
}
err = json.Unmarshal(body, &entities)
return entities, nil
}

func Reset(network *net.Network) (string, error) {
url := "/v1/catalog/reset"
body, err := network.SendEmptyPostRequest(url)
//Only deal with the below file types
if "" != u.Scheme && "file" != u.Scheme && "http" != u.Scheme && "https" != u.Scheme {
return nil, errors.New("Unrecognised protocol scheme: " + u.Scheme)
}

if "" == u.Scheme || "file" == u.Scheme {
if "file" == u.Scheme {
if u.Path == "" {
return nil, errors.New("No resource in 'file:' URL: " + resource)
}
resource = u.Path
}

file, err := os.Open(filepath.Clean(resource))
if err != nil {
return nil, err
}

fileStat, err := file.Stat()
if err != nil {
return nil, err
}

if fileStat.IsDir() {
//A dir is a special case, we need to zip it up, and call a different network method
buf, err := ZipResource(resource)
if err != nil {
return nil, err
}
body, err := network.SendPostRequestWithContentType(urlString, buf.Bytes(), "application/x-zip")
if err != nil {
return nil, err
}
err = json.Unmarshal(body, &entities)
return entities, err
} else {
extension := filepath.Ext(resource)
lowercaseExtension := strings.ToLower(extension)
if lowercaseExtension == ".zip" {
contentType = "application/x-zip"
} else if lowercaseExtension == ".jar" {
contentType = "application/x-jar"
}
}

}

body, err := network.SendPostResourceRequest(urlString, resource, contentType)
if err != nil {
return "", err
return nil, err
}
return string(body), nil
err = json.Unmarshal(body, &entities)

return entities, err
}

func GetLocation(network *net.Network, locationId string) (models.CatalogItemSummary, error) {
@@ -38,7 +38,7 @@ var appConfig = configDefaults{
Name: os.Args[0],
HelpName: os.Args[0],
Usage: "A Brooklyn command line client application",
Version: "0.11.0-SNAPSHOT", // BROOKLYN_VERSION
Version: "0.12.0-SNAPSHOT", // BROOKLYN_VERSION
}

func NewApp(baseName string, cmdRunner command_runner.Runner, metadatas ...command_metadata.CommandMetadata) (app *cli.App) {
@@ -41,13 +41,16 @@ func NewCatalogAdd(network *net.Network) (cmd *CatalogAdd) {
func (cmd *CatalogAdd) Metadata() command_metadata.CommandMetadata {
return command_metadata.CommandMetadata{
Name: "add",
Description: "Add a new catalog item from the supplied YAML (a file or http URL)",
Description: "Add catalog items from the supplied BOM YAML or from a ZIP or local folder containing a catalog.bom and optionally other resources",
Usage: "BROOKLYN_NAME catalog add ( FILEPATH | URL )",
Flags: []cli.Flag{},
}
}

func (cmd *CatalogAdd) Run(scope scope.Scope, c *cli.Context) {
if c.Args().First() == "" {
error_handler.ErrorExit("A filename or URL must be provided as the first argument", error_handler.CLIUsageErrorExitCode)
}
if err := net.VerifyLoginURL(cmd.network); err != nil {
error_handler.ErrorExit(err)
}

This file was deleted.

@@ -21,6 +21,7 @@ package error_handler
import (
"fmt"
"os"
"strconv"
"github.com/apache/brooklyn-client/cli/net"
)

@@ -32,7 +33,7 @@ func ErrorExit(errorvalue interface{}, errorcode ...int) {
switch errorvalue.(type) {
case net.HttpError:
httpError := errorvalue.(net.HttpError)
fmt.Fprintln(os.Stderr, httpError.Body)
fmt.Fprintln(os.Stderr, "Server error ("+strconv.Itoa(httpError.Code)+"): "+httpError.Body)
case error:
fmt.Fprintln(os.Stderr, errorvalue)
case string:
@@ -166,13 +166,17 @@ func (net *Network) SendEmptyPostRequest(url string) ([]byte, error) {
return body, err
}

func (net *Network) SendPostRequest(urlStr string, data []byte) ([]byte, error) {
func (net *Network) SendPostRequestWithContentType(urlStr string, data []byte, contentType string) ([]byte, error) {
req := net.NewPostRequest(urlStr, bytes.NewBuffer(data))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Content-Type", contentType)
body, err := net.SendRequest(req)
return body, err
}

func (net *Network) SendPostRequest(urlStr string, data []byte) ([]byte, error) {
return net.SendPostRequestWithContentType(urlStr, data, "application/json")
}

func (net *Network) SendPostResourceRequest(restUrl string, resourceUrl string, contentType string) ([]byte, error) {
resource, err := net.openResource(resourceUrl)
if err != nil {
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.brooklyn</groupId>
<artifactId>brooklyn-client</artifactId>
<version>0.11.0-SNAPSHOT</version> <!-- BROOKLYN_VERSION -->
<version>0.12.0-SNAPSHOT</version> <!-- BROOKLYN_VERSION -->
<relativePath>../pom.xml</relativePath>
</parent>

0 comments on commit 0260945

Please sign in to comment.