Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement concurrent manifest validation against Hub in CLI #437

Merged
merged 4 commits into from
Aug 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions cmd/cli/cmd/manifest/manifest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package manifest

import "github.com/spf13/cobra"

// NewCmd returns a cobra.Command for manifest related operations.
func NewCmd() *cobra.Command {
root := &cobra.Command{
Use: "manifest",
Aliases: []string{"mf"},
Short: "This command consists of multiple subcommands to interact with OCF manifests",
}

root.AddCommand(
NewValidate(),
)
return root
}
52 changes: 52 additions & 0 deletions cmd/cli/cmd/manifest/validate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package manifest

import (
"os"

"capact.io/capact/internal/cli/validate"

"capact.io/capact/internal/cli"
"capact.io/capact/internal/cli/heredoc"
"github.com/spf13/cobra"
)

const defaultMaxConcurrency int = 5

// NewValidate returns a cobra.Command for validating Hub Manifests.
func NewValidate() *cobra.Command {
var opts validate.Options

cmd := &cobra.Command{
Use: "validate",
pkosiec marked this conversation as resolved.
Show resolved Hide resolved
Short: "Validate OCF manifests",
Example: heredoc.WithCLIName(`
# Validate interface-group.yaml file with OCF specification in default location
<cli> manifest validate ocf-spec/0.0.1/examples/interface-group.yaml

# Validate multiple files inside test_manifests directory with additional server-side checks
<cli> manifest validate --server-side pkg/cli/test_manifests/*.yaml

# Validate all Hub manifests with additional server-side checks
<cli> manifest validate --server-side ./manifests/**/*.yaml

# Validate interface-group.yaml file with custom OCF specification location
<cli> manifest validate -s my/ocf/spec/directory ocf-spec/0.0.1/examples/interface-group.yaml`, cli.Name),
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
validation, err := validate.New(os.Stdout, opts)
if err != nil {
return err
}

return validation.Run(cmd.Context(), args)
},
}

flags := cmd.Flags()
flags.StringVarP(&opts.SchemaLocation, "schemas", "s", "", "Path to the local directory with OCF JSONSchemas. If not provided, built-in JSONSchemas are used.")
flags.BoolVarP(&opts.Verbose, "verbose", "v", false, "Prints more verbose output.")
pkosiec marked this conversation as resolved.
Show resolved Hide resolved
flags.BoolVar(&opts.ServerSide, "server-side", false, "Executes additional manifests checks against Capact Hub.")
flags.IntVar(&opts.MaxConcurrency, "concurrency", defaultMaxConcurrency, "Maximum number of concurrent workers.")

return cmd
}
3 changes: 2 additions & 1 deletion cmd/cli/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"capact.io/capact/cmd/cli/cmd/alpha"
"capact.io/capact/cmd/cli/cmd/environment"
"capact.io/capact/cmd/cli/cmd/manifest"
"capact.io/capact/cmd/cli/cmd/policy"

"capact.io/capact/cmd/cli/cmd/action"
Expand Down Expand Up @@ -76,14 +77,14 @@ func NewRoot() *cobra.Command {
rootCmd.PersistentFlags().StringVarP(&configPath, "config", "c", "", "Path to the YAML config file")

rootCmd.AddCommand(
NewValidate(),
NewDocs(),
NewLogin(),
NewLogout(),
NewInstall(),
NewUpgrade(),
NewCompletion(),
NewVersion(),
manifest.NewCmd(),
hub.NewCmd(),
configcmd.NewCmd(),
action.NewCmd(),
Expand Down
68 changes: 0 additions & 68 deletions cmd/cli/cmd/validate.go

This file was deleted.

2 changes: 1 addition & 1 deletion cmd/cli/docs/capact.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ capact [flags]
* [capact install](capact_install.md) - install Capact into a given environment
* [capact login](capact_login.md) - Login to a Hub (Gateway) server
* [capact logout](capact_logout.md) - Logout from the Hub (Gateway) server
* [capact manifest](capact_manifest.md) - This command consists of multiple subcommands to interact with OCF manifests
* [capact policy](capact_policy.md) - This command consists of multiple subcommands to interact with Policy
* [capact typeinstance](capact_typeinstance.md) - This command consists of multiple subcommands to interact with target TypeInstances
* [capact upgrade](capact_upgrade.md) - Upgrades Capact
* [capact validate](capact_validate.md) - Validate OCF manifests
* [capact version](capact_version.md) - Show version information about this binary

25 changes: 25 additions & 0 deletions cmd/cli/docs/capact_manifest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
title: capact manifest
---

## capact manifest

This command consists of multiple subcommands to interact with OCF manifests

### Options

```
-h, --help help for manifest
```

### Options inherited from parent commands

```
-c, --config string Path to the YAML config file
```

### SEE ALSO

* [capact](capact.md) - Collective Capability Manager CLI
* [capact manifest validate](capact_manifest_validate.md) - Validate OCF manifests

48 changes: 48 additions & 0 deletions cmd/cli/docs/capact_manifest_validate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: capact manifest validate
---

## capact manifest validate

Validate OCF manifests

```
capact manifest validate [flags]
```

### Examples

```
# Validate interface-group.yaml file with OCF specification in default location
capact manifest validate ocf-spec/0.0.1/examples/interface-group.yaml

# Validate multiple files inside test_manifests directory with additional server-side checks
capact manifest validate --server-side pkg/cli/test_manifests/*.yaml

# Validate all Hub manifests with additional server-side checks
capact manifest validate --server-side ./manifests/**/*.yaml

# Validate interface-group.yaml file with custom OCF specification location
capact manifest validate -s my/ocf/spec/directory ocf-spec/0.0.1/examples/interface-group.yaml
```

### Options

```
--concurrency int Maximum number of concurrent workers. (default 5)
-h, --help help for validate
-s, --schemas string Path to the local directory with OCF JSONSchemas. If not provided, built-in JSONSchemas are used.
--server-side Executes additional manifests checks against Capact Hub.
-v, --verbose Prints more verbose output.
```

### Options inherited from parent commands

```
-c, --config string Path to the YAML config file
```

### SEE ALSO

* [capact manifest](capact_manifest.md) - This command consists of multiple subcommands to interact with OCF manifests

24 changes: 23 additions & 1 deletion cmd/cli/main.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,37 @@
package main

import (
"context"
"os"
"os/signal"
"syscall"

"capact.io/capact/cmd/cli/cmd"
)

func main() {
rootCmd := cmd.NewRoot()
ctx, cancel := cancelableContext()
defer cancel()

if err := rootCmd.Execute(); err != nil {
if err := rootCmd.ExecuteContext(ctx); err != nil {
os.Exit(1)
}
}

// cancelableContext returns context that is canceled when stop signal is received
func cancelableContext() (context.Context, context.CancelFunc) {
ctx, cancel := context.WithCancel(context.Background())
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)

go func() {
select {
case <-ctx.Done():
case <-sigCh:
cancel()
}
}()

return ctx, cancel
}
3 changes: 1 addition & 2 deletions internal/cli/alpha/manifestgen/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"fmt"
"strings"

"capact.io/capact/pkg/sdk/manifest"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -65,7 +64,7 @@ func GenerateInterfaceManifests(cfg *InterfaceConfig) (map[string]string, error)
result := make(map[string]string, len(generated))

for _, m := range generated {
metadata, err := manifest.GetMetadata([]byte(m))
metadata, err := unmarshalMetadata([]byte(m))
if err != nil {
return nil, errors.Wrap(err, "while getting metadata for manifest")
}
Expand Down
26 changes: 26 additions & 0 deletions internal/cli/alpha/manifestgen/metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package manifestgen

import (
"capact.io/capact/pkg/sdk/apis/0.0.1/types"
"sigs.k8s.io/yaml"
)

// Metadata holds generic metadata information for Capact manifests.
type Metadata struct {
OCFVersion types.OcfVersion `yaml:"ocfVersion"`
Kind types.ManifestKind `yaml:"kind"`
Metadata struct {
Name string `yaml:"name"`
Prefix string `yaml:"prefix"`
} `yaml:"metadata"`
}

// unmarshalMetadata reads the manifest metadata from a bytes lice of a Capact manifest.
func unmarshalMetadata(yamlBytes []byte) (Metadata, error) {
mm := Metadata{}
err := yaml.Unmarshal(yamlBytes, &mm)
if err != nil {
return mm, err
}
return mm, nil
}
3 changes: 1 addition & 2 deletions internal/cli/alpha/manifestgen/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"sort"
"strings"

"capact.io/capact/pkg/sdk/manifest"
"github.com/hashicorp/terraform-config-inspect/tfconfig"
"github.com/pkg/errors"
)
Expand Down Expand Up @@ -56,7 +55,7 @@ func GenerateTerraformManifests(cfg *TerraformConfig) (map[string]string, error)
result := make(map[string]string, len(generated))

for _, m := range generated {
metadata, err := manifest.GetMetadata([]byte(m))
metadata, err := unmarshalMetadata([]byte(m))
if err != nil {
return nil, errors.Wrap(err, "while getting metadata for manifest")
}
Expand Down
1 change: 1 addition & 0 deletions internal/cli/client/hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type Hub interface {
CreateTypeInstances(ctx context.Context, in *gqllocalapi.CreateTypeInstancesInput) ([]gqllocalapi.CreateTypeInstanceOutput, error)
UpdateTypeInstances(ctx context.Context, in []gqllocalapi.UpdateTypeInstancesInput) ([]gqllocalapi.TypeInstance, error)
DeleteTypeInstance(ctx context.Context, id string) error
CheckManifestRevisionsExist(ctx context.Context, manifestRefs []gqlpublicapi.ManifestReference) (map[gqlpublicapi.ManifestReference]bool, error)
}

// NewHub returns client for Capact Hub configured with saved credentials for a given server URL.
Expand Down
12 changes: 5 additions & 7 deletions internal/cli/schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"net/http"
"os"
"path/filepath"

"github.com/spf13/pflag"
)

//go:generate go run embed_schema.go
Expand All @@ -15,6 +13,11 @@ type Provider struct {
localSchemaRootDir string
}

// NewProvider instantiates new Provider.
func NewProvider(localSchemaRootDir string) *Provider {
return &Provider{localSchemaRootDir: localSchemaRootDir}
}

// FileSystem returns file system implementation and root dir for schema directory.
func (s *Provider) FileSystem() (http.FileSystem, string) {
if len(s.localSchemaRootDir) != 0 {
Expand All @@ -24,11 +27,6 @@ func (s *Provider) FileSystem() (http.FileSystem, string) {
return Static, "."
}

// RegisterSchemaFlags registers schema related flags
func (s *Provider) RegisterSchemaFlags(flagSet *pflag.FlagSet) {
flagSet.StringVarP(&s.localSchemaRootDir, "schemas", "s", "", "Path to the local directory with OCF JSONSchemas. If not provided, built-in JSONSchemas are used.")
}

// LocalFileSystem fulfils the http.FileSystem interface and provides functionality to open files from local file system.
type LocalFileSystem struct{}

Expand Down
Loading