Skip to content

Commit

Permalink
Merge pull request #64 from foundriesio/compose-apps
Browse files Browse the repository at this point in the history
add support for compose apps to a target show command
  • Loading branch information
vkhoroz authored Nov 18, 2020
2 parents ea13b93 + 7bd14f9 commit 301ca87
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 32 deletions.
44 changes: 44 additions & 0 deletions client/foundries.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,19 @@ type TufCustom struct {
OverridesSha string `json:"meta-subscriber-overrides-sha,omitempty"`
}

type ComposeAppContent struct {
Files []string `json:"files"`
ComposeSpec map[string]interface{} `json:"compose_spec"`
}

type ComposeAppBundle struct {
Uri string `json:"uri"`
Error string `json:"error"`
Warnings []string `json:"warnings"`
Manifest map[string]interface{} `json:"manifest"`
Content ComposeAppContent `json:"content"`
}

type TargetTestResults struct {
Name string `json:"name"`
Status string `json:"status"`
Expand Down Expand Up @@ -703,6 +716,37 @@ func (a *Api) TargetImageCreate(factory string, targetName string, appShortlist
return getResponse(resp, err, "assemble-system-image")
}

// Return a Compose App for a given Target by a Target ID and an App name
func (a *Api) TargetComposeApp(factory string, targetName string, app string) (*ComposeAppBundle, error) {
url := a.serverUrl + "/ota/factories/" + factory + "/targets/" + targetName + "/compose-apps/" + app + "/"
log := logrus.WithFields(logrus.Fields{"url": url})
logrus.Debugf("TargetApp with url: %s", url)

resp, err := a.RawGet(url, nil)
if err != nil {
log.Errorf("Network Error: %s", err)
return nil, err
} else if resp.StatusCode != 200 {
log.WithFields(logrus.Fields{"status": resp.StatusCode}).Errorf("HTTP Error: %s", resp.Status)
// Don't return, we can get some debug info from response.
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Errorf("I/O Error: %s", err)
return nil, err
}

result := ComposeAppBundle{}
if err = json.Unmarshal(body, &result); err != nil {
log.Errorf("Parse Error: %s", err)
return nil, fmt.Errorf("Parse Error: %w\n=for '%s' HTTP response: %s\n=%s", err, url, resp.Status, body)
} else {
return &result, nil
}
}

// Return a list of Targets that have been tested
func (a *Api) TargetTesting(factory string) ([]int, error) {
url := a.serverUrl + "/ota/factories/" + factory + "/testing/"
Expand Down
11 changes: 5 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6 h1:Eey/GGQ/E5Xp1P2Lyx1qj007hLZfbi0+CoVeJruGCtI=
github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
Expand Down Expand Up @@ -89,8 +90,10 @@ github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJo
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
Expand Down Expand Up @@ -161,9 +164,9 @@ github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
github.com/theupdateframework/notary v0.6.1 h1:7wshjstgS9x9F5LuB1L5mBI2xNMObWqjz+cjWoom6l0=
Expand All @@ -173,7 +176,6 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 h1:QmwruyY+bKbDDL0BaglrbZABEali68eoMFhTZpCjYVA=
Expand All @@ -189,21 +191,18 @@ golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
Expand Down
139 changes: 113 additions & 26 deletions subcommands/targets/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,50 +10,43 @@ import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"gopkg.in/yaml.v2"

"github.com/foundriesio/fioctl/client"
)

func init() {
cmd.AddCommand(&cobra.Command{
showCmd := &cobra.Command{
Use: "show <version>",
Short: "Show details of a specific target.",
Run: doShow,
Args: cobra.ExactArgs(1),
})
}
cmd.AddCommand(showCmd)

showAppCmd := &cobra.Command{
Use: "compose-app <version> <app>",
Short: "Show details of a specific compose app.",
Run: doShowComposeApp,
Args: cobra.ExactArgs(2),
}
showCmd.AddCommand(showAppCmd)
showAppCmd.Flags().Bool("manifest", false, "Show an app docker manifest")
}

func doShow(cmd *cobra.Command, args []string) {
factory := viper.GetString("factory")
logrus.Debugf("Showing target for %s %s", factory, args[0])

targets, err := api.TargetsList(factory)
if err != nil {
fmt.Print("ERROR: ")
fmt.Println(err)
os.Exit(1)
}
version := args[0]
logrus.Debugf("Showing target for %s %s", factory, version)

hashes := make(map[string]string)
var tags []string
var apps map[string]client.DockerApp
var composeApps map[string]client.ComposeApp
containersSha := ""
manifestSha := ""
overridesSha := ""
for name, target := range targets.Signed.Targets {
custom, err := api.TargetCustom(target)
if err != nil {
fmt.Printf("ERROR: %s\n", err)
continue
}
if custom.Version != args[0] {
continue
}
if custom.TargetFormat != "OSTREE" {
logrus.Debugf("Skipping non-ostree target: %v", target)
continue
}
hashes, targets := getTargets(factory, version)
for _, custom := range targets {
if len(custom.ContainersSha) > 0 {
if len(containersSha) > 0 && containersSha != custom.ContainersSha {
fmt.Println("ERROR: Git hashes for containers.git does not match across platforms")
Expand All @@ -75,15 +68,14 @@ func doShow(cmd *cobra.Command, args []string) {
}
overridesSha = custom.OverridesSha
}
hashes[name] = base64.StdEncoding.EncodeToString(target.Hashes["sha256"])
apps = custom.DockerApps
composeApps = custom.ComposeApps
tags = custom.Tags
}

fmt.Printf("Tags:\t%s\n", strings.Join(tags, ","))

fmt.Printf("CI:\thttps://ci.foundries.io/projects/%s/lmp/builds/%s/\n", factory, args[0])
fmt.Printf("CI:\thttps://ci.foundries.io/projects/%s/lmp/builds/%s/\n", factory, version)

fmt.Println("Source:")
if len(manifestSha) > 0 {
Expand Down Expand Up @@ -131,3 +123,98 @@ func doShow(cmd *cobra.Command, args []string) {
t.Print()
}
}

func doShowComposeApp(cmd *cobra.Command, args []string) {
factory := viper.GetString("factory")
version := args[0]
appName := args[1]
logrus.Debugf("Showing target for %s %s %s", factory, version, appName)

_, targets := getTargets(factory, version)
for name, custom := range targets {
_, ok := custom.ComposeApps[appName]
if !ok {
fmt.Println("ERROR: App not found in target")
os.Exit(1)
}
appInfo, err := api.TargetComposeApp(factory, name, appName)
if err != nil {
fmt.Println("ERROR:", err)
os.Exit(1)
}

fmt.Println("Version:\n\t", appInfo.Uri)
if len(appInfo.Error) > 0 {
fmt.Println("Error:\n\t", appInfo.Error)
}
if appInfo.Warnings != nil {
fmt.Println("Warnings:")
for _, warn := range appInfo.Warnings {
fmt.Println("\t", warn)
}
}

if appInfo.Manifest != nil {
if showManifest, _ := cmd.Flags().GetBool("manifest"); showManifest {
fmt.Println("\nDocker Manifest:")
// If a JSON unmarshal worked - YAML marshal will also work
manifest, _ := yaml.Marshal(appInfo.Manifest)
fmt.Println(indent(strings.TrimSpace(string(manifest)), "\t"))
}
}

if appInfo.Content.Files != nil {
fmt.Println("\nFiles:")
for _, file := range appInfo.Content.Files {
fmt.Println("\t", file)
}
}

if appInfo.Content.ComposeSpec != nil {
fmt.Println("\nDocker Compose Template:")
// If a JSON unmarshal worked - YAML marshal will also work
composeSpec, _ := yaml.Marshal(appInfo.Content.ComposeSpec)
fmt.Println(indent(strings.TrimSpace(string(composeSpec)), "\t"))
}

// all targets contain the same compose apps, so only print once
break
}
}

func getTargets(factory string, version string) (map[string]string, map[string]client.TufCustom) {
targetsJson, err := api.TargetsList(factory)
if err != nil {
fmt.Print("ERROR: ")
fmt.Println(err)
os.Exit(1)
}

hashes := make(map[string]string)
matches := make(map[string]client.TufCustom)
for name, target := range targetsJson.Signed.Targets {
custom, err := api.TargetCustom(target)
if err != nil {
fmt.Printf("ERROR: %s\n", err)
continue
}
if custom.Version != version {
continue
}
if custom.TargetFormat != "OSTREE" {
logrus.Debugf("Skipping non-ostree target: %v", target)
continue
}
matches[name] = *custom
hashes[name] = base64.StdEncoding.EncodeToString(target.Hashes["sha256"])
}
if len(matches) == 0 {
fmt.Println("ERROR: no OSTREE target found for this version")
os.Exit(1)
}
return hashes, matches
}

func indent(input string, prefix string) string {
return prefix + strings.Join(strings.SplitAfter(input, "\n"), prefix)
}

0 comments on commit 301ca87

Please sign in to comment.