Skip to content
This repository has been archived by the owner on Oct 14, 2024. It is now read-only.

Commit

Permalink
fix(cli): subcommands (#513)
Browse files Browse the repository at this point in the history
* fix(cli): subcommands

* fix(cli): subcmd

* fix(cli): lint error
  • Loading branch information
pbalogh-sa authored Aug 1, 2023
1 parent 7c4c951 commit 0ad3bd4
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 69 deletions.
42 changes: 20 additions & 22 deletions cmd/vmclarity-cli/asset/asset_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,69 +24,67 @@ import (

"github.com/spf13/cobra"

"github.com/openclarity/vmclarity/cmd/vmclarity-cli/root"
"github.com/openclarity/vmclarity/cmd/vmclarity-cli/logutil"
cliutils "github.com/openclarity/vmclarity/pkg/cli/utils"

"github.com/openclarity/vmclarity/api/models"
"github.com/openclarity/vmclarity/pkg/shared/backendclient"
)

// assetCreateCmd represents the standalone command.
var assetCreateCmd = &cobra.Command{
// AssetCreateCmd represents the standalone command.
var AssetCreateCmd = &cobra.Command{
Use: "asset-create",
Short: "Create asset",
Long: `It creates asset. It's useful in the CI/CD mode without VMClarity orchestration`,
Run: func(cmd *cobra.Command, args []string) {
root.Logger.Infof("Creating asset...")
logutil.Logger.Infof("Creating asset...")
filename, err := cmd.Flags().GetString("file")
if err != nil {
root.Logger.Fatalf("Unable to get asset json file name: %v", err)
logutil.Logger.Fatalf("Unable to get asset json file name: %v", err)
}
server, err := cmd.Flags().GetString("server")
if err != nil {
root.Logger.Fatalf("Unable to get VMClarity server address: %v", err)
logutil.Logger.Fatalf("Unable to get VMClarity server address: %v", err)
}
assetType, err := getAssetFromJSONFile(filename)
if err != nil {
root.Logger.Fatalf("Failed to get asset from json file: %v", err)
logutil.Logger.Fatalf("Failed to get asset from json file: %v", err)
}
updateIfExists, err := cmd.Flags().GetBool("update-if-exists")
if err != nil {
root.Logger.Fatalf("Unable to get update-if-exists flag vaule: %v", err)
logutil.Logger.Fatalf("Unable to get update-if-exists flag vaule: %v", err)
}
jsonPath, err := cmd.Flags().GetString("jsonpath")
if err != nil {
root.Logger.Fatalf("Unable to get jsonpath: %v", err)
logutil.Logger.Fatalf("Unable to get jsonpath: %v", err)
}

_, err = assetType.ValueByDiscriminator()
if err != nil {
root.Logger.Fatalf("Failed to determine asset type: %v", err)
logutil.Logger.Fatalf("Failed to determine asset type: %v", err)
}

asset, err := createAsset(context.TODO(), assetType, server, updateIfExists)
if err != nil {
root.Logger.Fatalf("Failed to create asset: %v", err)
logutil.Logger.Fatalf("Failed to create asset: %v", err)
}

if err := cliutils.PrintJSONData(asset, jsonPath); err != nil {
root.Logger.Fatalf("Failed to print jsonpath: %v", err)
logutil.Logger.Fatalf("Failed to print jsonpath: %v", err)
}
},
}

func init() {
root.RootCmd.AddCommand(assetCreateCmd)

assetCreateCmd.Flags().String("file", "", "asset json filename")
assetCreateCmd.Flags().String("server", "", "VMClarity server to create asset to, for example: http://localhost:9999/api")
assetCreateCmd.Flags().Bool("update-if-exists", false, "the asset will be updated the asset if it exists")
assetCreateCmd.Flags().String("jsonpath", "", "print selected value of asset")
if err := assetCreateCmd.MarkFlagRequired("file"); err != nil {
root.Logger.Fatalf("Failed to mark file flag as required: %v", err)
AssetCreateCmd.Flags().String("file", "", "asset json filename")
AssetCreateCmd.Flags().String("server", "", "VMClarity server to create asset to, for example: http://localhost:9999/api")
AssetCreateCmd.Flags().Bool("update-if-exists", false, "the asset will be updated the asset if it exists")
AssetCreateCmd.Flags().String("jsonpath", "", "print selected value of asset")
if err := AssetCreateCmd.MarkFlagRequired("file"); err != nil {
logutil.Logger.Fatalf("Failed to mark file flag as required: %v", err)
}
if err := assetCreateCmd.MarkFlagRequired("server"); err != nil {
root.Logger.Fatalf("Failed to mark server flag as required: %v", err)
if err := AssetCreateCmd.MarkFlagRequired("server"); err != nil {
logutil.Logger.Fatalf("Failed to mark server flag as required: %v", err)
}
}

Expand Down
35 changes: 17 additions & 18 deletions cmd/vmclarity-cli/asset/asset_scan_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,55 +22,54 @@ import (

"github.com/spf13/cobra"

"github.com/openclarity/vmclarity/cmd/vmclarity-cli/root"
"github.com/openclarity/vmclarity/cmd/vmclarity-cli/logutil"
cliutils "github.com/openclarity/vmclarity/pkg/cli/utils"

"github.com/openclarity/vmclarity/api/models"
"github.com/openclarity/vmclarity/pkg/shared/backendclient"
"github.com/openclarity/vmclarity/pkg/shared/utils"
)

// assetScanCreateCmd represents the standalone command.
var assetScanCreateCmd = &cobra.Command{
// AssetScanCreateCmd represents the standalone command.
var AssetScanCreateCmd = &cobra.Command{
Use: "asset-scan-create",
Short: "Create asset scan",
Long: `It creates asset scan. It's useful in the CI/CD mode without VMClarity orchestration`,
Run: func(cmd *cobra.Command, args []string) {
root.Logger.Infof("asset-scan-create called")
logutil.Logger.Infof("asset-scan-create called")
assetID, err := cmd.Flags().GetString("asset-id")
if err != nil {
root.Logger.Fatalf("Unable to get asset id: %v", err)
logutil.Logger.Fatalf("Unable to get asset id: %v", err)
}
server, err := cmd.Flags().GetString("server")
if err != nil {
root.Logger.Fatalf("Unable to get VMClarity server address: %v", err)
logutil.Logger.Fatalf("Unable to get VMClarity server address: %v", err)
}
jsonPath, err := cmd.Flags().GetString("jsonpath")
if err != nil {
root.Logger.Fatalf("Unable to get jsonpath: %v", err)
logutil.Logger.Fatalf("Unable to get jsonpath: %v", err)
}

assetScan, err := createAssetScan(context.TODO(), server, assetID)
if err != nil {
root.Logger.Fatalf("Failed to create asset scan: %v", err)
logutil.Logger.Fatalf("Failed to create asset scan: %v", err)
}

if err := cliutils.PrintJSONData(assetScan, jsonPath); err != nil {
root.Logger.Fatalf("Failed to print jsonpath: %v", err)
logutil.Logger.Fatalf("Failed to print jsonpath: %v", err)
}
},
}

func init() {
root.RootCmd.AddCommand(assetScanCreateCmd)
assetScanCreateCmd.Flags().String("server", "", "VMClarity server to create asset to, for example: http://localhost:9999/api")
assetScanCreateCmd.Flags().String("asset-id", "", "Asset ID for asset scan")
assetScanCreateCmd.Flags().String("jsonpath", "", "print selected value of asset scan")
if err := assetScanCreateCmd.MarkFlagRequired("server"); err != nil {
root.Logger.Fatalf("Failed to mark server flag as required: %v", err)
AssetScanCreateCmd.Flags().String("server", "", "VMClarity server to create asset to, for example: http://localhost:9999/api")
AssetScanCreateCmd.Flags().String("asset-id", "", "Asset ID for asset scan")
AssetScanCreateCmd.Flags().String("jsonpath", "", "print selected value of asset scan")
if err := AssetScanCreateCmd.MarkFlagRequired("server"); err != nil {
logutil.Logger.Fatalf("Failed to mark server flag as required: %v", err)
}
if err := assetScanCreateCmd.MarkFlagRequired("asset-id"); err != nil {
root.Logger.Fatalf("Failed to mark asset-id flag as required: %v", err)
if err := AssetScanCreateCmd.MarkFlagRequired("asset-id"); err != nil {
logutil.Logger.Fatalf("Failed to mark asset-id flag as required: %v", err)
}
}

Expand All @@ -91,7 +90,7 @@ func createAssetScan(ctx context.Context, server, assetID string) (*models.Asset
var conErr backendclient.AssetScanConflictError
if errors.As(err, &conErr) {
assetScanID := *conErr.ConflictingAssetScan.Id
root.Logger.WithField("AssetScanID", assetScanID).Debug("AssetScan already exist.")
logutil.Logger.WithField("AssetScanID", assetScanID).Debug("AssetScan already exist.")
return conErr.ConflictingAssetScan, nil
}
return nil, fmt.Errorf("failed to post AssetScan to backend API: %w", err)
Expand Down
22 changes: 22 additions & 0 deletions cmd/vmclarity-cli/logutil/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright © 2023 Cisco Systems, Inc. and its affiliates.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package logutil

import (
"github.com/sirupsen/logrus"
)

var Logger *logrus.Entry
14 changes: 9 additions & 5 deletions cmd/vmclarity-cli/root/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"

"github.com/openclarity/vmclarity/cmd/vmclarity-cli/asset"
"github.com/openclarity/vmclarity/cmd/vmclarity-cli/logutil"
"github.com/openclarity/vmclarity/cmd/vmclarity-cli/scan"
"github.com/openclarity/vmclarity/pkg/cli"
"github.com/openclarity/vmclarity/pkg/shared/log"
)

var Logger *logrus.Entry

// RootCmd represents the base command when called without any subcommands.
var RootCmd = &cobra.Command{
var rootCmd = &cobra.Command{
Use: "vmclarity",
Short: "VMClarity",
Long: `VMClarity`,
Expand All @@ -39,17 +40,20 @@ var RootCmd = &cobra.Command{
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
cobra.CheckErr(RootCmd.Execute())
cobra.CheckErr(rootCmd.Execute())
}

// nolint: gochecknoinits
func init() {
cobra.OnInitialize(
initLogger,
)
rootCmd.AddCommand(scan.ScanCmd)
rootCmd.AddCommand(asset.AssetCreateCmd)
rootCmd.AddCommand(asset.AssetScanCreateCmd)
}

func initLogger() {
log.InitLogger(logrus.InfoLevel.String(), os.Stderr)
Logger = logrus.WithField("app", "vmclarity")
logutil.Logger = logrus.WithField("app", "vmclarity")
}
46 changes: 22 additions & 24 deletions cmd/vmclarity-cli/scan/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/openclarity/vmclarity/cmd/vmclarity-cli/root"
"github.com/openclarity/vmclarity/cmd/vmclarity-cli/logutil"
"github.com/openclarity/vmclarity/pkg/cli"

"github.com/openclarity/vmclarity/pkg/cli/state"
Expand All @@ -44,37 +44,37 @@ const (
DefaultMountTimeout = 10 * time.Minute
)

// scanCmd represents the scan command.
var scanCmd = &cobra.Command{
// ScanCmd represents the scan command.
var ScanCmd = &cobra.Command{
Use: "scan",
Short: "Scan",
Long: `Run scanner families`,
RunE: func(cmd *cobra.Command, args []string) error {
root.Logger.Infof("Running...")
logutil.Logger.Infof("Running...")

// Main context which remains active even if the scan is aborted allowing post-processing operations
// like updating asset scan state
ctx := log.SetLoggerForContext(cmd.Context(), root.Logger)
ctx := log.SetLoggerForContext(cmd.Context(), logutil.Logger)

cfgFile, err := cmd.Flags().GetString("config")
if err != nil {
root.Logger.Fatalf("Unable to get config file name: %v", err)
logutil.Logger.Fatalf("Unable to get config file name: %v", err)
}
server, err := cmd.Flags().GetString("server")
if err != nil {
root.Logger.Fatalf("Unable to get VMClarity server address: %v", err)
logutil.Logger.Fatalf("Unable to get VMClarity server address: %v", err)
}
output, err := cmd.Flags().GetString("output")
if err != nil {
root.Logger.Fatalf("Unable to get output file name: %v", err)
logutil.Logger.Fatalf("Unable to get output file name: %v", err)
}
assetScanID, err := cmd.Flags().GetString("asset-scan-id")
if err != nil {
root.Logger.Fatalf("Unable to get asset scan ID: %v", err)
logutil.Logger.Fatalf("Unable to get asset scan ID: %v", err)
}
mountVolume, err := cmd.Flags().GetBool("mount-attached-volume")
if err != nil {
root.Logger.Fatalf("Unable to get mount attached volume flag: %v", err)
logutil.Logger.Fatalf("Unable to get mount attached volume flag: %v", err)
}

config := loadConfig(cfgFile)
Expand All @@ -93,7 +93,7 @@ var scanCmd = &cobra.Command{
if err := cli.WaitForReadyState(abortCtx); err != nil {
err = fmt.Errorf("failed to wait for AssetScan being ready to scan: %w", err)
if e := cli.MarkDone(ctx, []error{err}); e != nil {
root.Logger.Errorf("Failed to update AssetScan status to completed with errors: %v", e)
logutil.Logger.Errorf("Failed to update AssetScan status to completed with errors: %v", e)
}
return err
}
Expand All @@ -107,7 +107,7 @@ var scanCmd = &cobra.Command{
if err != nil {
err = fmt.Errorf("failed to mount attached volume: %w", err)
if e := cli.MarkDone(ctx, []error{err}); e != nil {
root.Logger.Errorf("Failed to update asset scan stat to completed with errors: %v", e)
logutil.Logger.Errorf("Failed to update asset scan stat to completed with errors: %v", e)
}
return err
}
Expand All @@ -119,7 +119,7 @@ var scanCmd = &cobra.Command{
return fmt.Errorf("failed to inform server %v scan has started: %w", server, err)
}

root.Logger.Infof("Running scanners...")
logutil.Logger.Infof("Running scanners...")
runErrors := families.New(config).Run(abortCtx, cli)

err = cli.MarkDone(ctx, runErrors)
Expand All @@ -128,7 +128,7 @@ var scanCmd = &cobra.Command{
}

if len(runErrors) > 0 {
root.Logger.Errorf("Errors when running families: %+v", runErrors)
logutil.Logger.Errorf("Errors when running families: %+v", runErrors)
}

return nil
Expand All @@ -137,26 +137,24 @@ var scanCmd = &cobra.Command{

// nolint: gochecknoinits
func init() {
root.RootCmd.AddCommand(scanCmd)

// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
scanCmd.Flags().String("config", "", "config file (default is $HOME/.vmclarity.yaml)")
scanCmd.Flags().String("output", "", "set output directory path. Stdout is used if not set.")
scanCmd.Flags().String("server", "", "VMClarity server to export asset scans to, for example: http://localhost:9999/api")
scanCmd.Flags().String("asset-scan-id", "", "the AssetScan ID to monitor and report results to")
scanCmd.Flags().Bool("mount-attached-volume", false, "discover for an attached volume and mount it before the scan")
ScanCmd.Flags().String("config", "", "config file (default is $HOME/.vmclarity.yaml)")
ScanCmd.Flags().String("output", "", "set output directory path. Stdout is used if not set.")
ScanCmd.Flags().String("server", "", "VMClarity server to export asset scans to, for example: http://localhost:9999/api")
ScanCmd.Flags().String("asset-scan-id", "", "the AssetScan ID to monitor and report results to")
ScanCmd.Flags().Bool("mount-attached-volume", false, "discover for an attached volume and mount it before the scan")

// TODO(sambetts) we may have to change this to our own validation when
// we add the CI/CD scenario and there isn't an existing asset-scan-id
// in the backend to PATCH
scanCmd.MarkFlagsRequiredTogether("server", "asset-scan-id")
ScanCmd.MarkFlagsRequiredTogether("server", "asset-scan-id")
}

// loadConfig reads in config file and ENV variables if set.
func loadConfig(cfgFile string) *families.Config {
root.Logger.Infof("Initializing configuration...")
logutil.Logger.Infof("Initializing configuration...")
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
Expand Down Expand Up @@ -186,7 +184,7 @@ func loadConfig(cfgFile string) *families.Config {
if logrus.IsLevelEnabled(logrus.InfoLevel) {
configB, err := yaml.Marshal(config)
cobra.CheckErr(err)
root.Logger.Infof("Using config file (%s):\n%s", viper.ConfigFileUsed(), string(configB))
logutil.Logger.Infof("Using config file (%s):\n%s", viper.ConfigFileUsed(), string(configB))
}

return config
Expand Down

0 comments on commit 0ad3bd4

Please sign in to comment.