Skip to content

Commit

Permalink
Merge pull request #38 from kurtismullins/ccs
Browse files Browse the repository at this point in the history
Use CCS in `create-cluster` test
  • Loading branch information
kurtismullins authored Jun 28, 2021
2 parents 8552cea + abf0aad commit 1c06b20
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 37 deletions.
90 changes: 65 additions & 25 deletions cmd/ocm-load-test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,23 @@ var rootCmd = &cobra.Command{

func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&configFile, "config-file", "config.yaml", "config file")
rootCmd.PersistentFlags().String("ocm-token-url", "https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token", "Token URL")
rootCmd.PersistentFlags().String("ocm-token", "", "OCM Authorization token")
rootCmd.PersistentFlags().String("gateway-url", "https://api.integration.openshift.com", "Gateway url to perform the test against")
rootCmd.PersistentFlags().String("test-id", uuid.NewV4().String(), "Unique ID to identify the test run. UUID is recommended")
rootCmd.PersistentFlags().String("output-path", "results", "Output directory for result and report files")
rootCmd.PersistentFlags().Int("duration", 1, "Duration of each individual run in minutes.")
rootCmd.PersistentFlags().String("rate", "1/s", "Rate of the attack. Format example 5/s. (Available units 'ns', 'us', 'ms', 's', 'm', 'h')")
rootCmd.PersistentFlags().StringSlice("test-names", []string{}, "Names for the tests to be run.")
rootCmd.PersistentFlags().BoolP("verbose", "v", false, "set this flag to activate verbose logging.")
rootCmd.PersistentFlags().Int("cooldown", 10, "Cooldown time between tests in seconds.")
rootCmd.Flags().StringVar(&configFile, "config-file", "config.yaml", "config file")
rootCmd.Flags().String("ocm-token-url", "https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token", "Token URL")
rootCmd.Flags().String("ocm-token", "", "OCM Authorization token")
rootCmd.Flags().String("gateway-url", "https://api.integration.openshift.com", "Gateway url to perform the test against")
rootCmd.Flags().String("test-id", uuid.NewV4().String(), "Unique ID to identify the test run. UUID is recommended")
rootCmd.Flags().String("output-path", "results", "Output directory for result and report files")
rootCmd.Flags().Int("duration", 1, "Duration of each individual run in minutes.")
rootCmd.Flags().String("rate", "1/s", "Rate of the attack. Format example 5/s. (Available units 'ns', 'us', 'ms', 's', 'm', 'h')")
rootCmd.Flags().StringSlice("test-names", []string{}, "Names for the tests to be run.")
rootCmd.Flags().BoolP("verbose", "v", false, "set this flag to activate verbose logging.")
rootCmd.Flags().Int("cooldown", 10, "Cooldown time between tests in seconds.")
// AWS config
// If needed to use multiple AWS account, use the config file
rootCmd.Flags().String("aws-region", "us-west-1", "AWS region")
rootCmd.Flags().String("aws-access-key", "", "AWS access key")
rootCmd.Flags().String("aws-access-secret", "", "AWS access secret")
rootCmd.Flags().String("aws-account-id", "", "AWS Account ID, is the 12-digit account number.")
rootCmd.AddCommand(cmd.NewVersionCommand())
}

Expand All @@ -77,6 +83,52 @@ func initConfig() {
}
}

// configTests decides wether to use Flags values or config file
func configTests() {
// Flag overrides config
// Selecting test passed in the Flag
if len(viper.GetStringSlice("test-names")) > 0 {
viper.Set("tests", map[string]interface{}{})
tests := viper.GetStringSlice("test-names")
for _, t := range tests {
viper.Set(fmt.Sprintf("tests.%s", t), map[string]interface{}{})
}
}

// If no Flag or Config is passed all test should run
if len(viper.GetStringSlice("test-names")) == 0 && len(viper.GetStringMap("tests")) == 0 {
viper.Set("tests.all", map[string]interface{}{})
}
}

// configAWS decides wether to use Flags values or config file
func configAWS(ctx context.Context, logger *logging.GoLogger) {
// Flag overrides config
// Selecting test passed in the Flag
if viper.GetString("aws-account-id") != "" {
if viper.GetString("aws-access-key") == "" || viper.GetString("aws-access-secret") == "" {
logger.Fatal(ctx, "AWS configuration not complete")
}
config := []interface{}{map[interface{}]interface{}{
"region": viper.GetString("aws-region"),
"access-key": viper.GetString("aws-access-key"),
"secret-access-key": viper.GetString("aws-access-secret"),
"account-id": viper.GetString("aws-account-id"),
}}
viper.Set("aws", config)
}

// If no Flag or Config is passed all test should run
if len(viper.Get("aws").([]interface{})) < 1 {
logger.Fatal(ctx, "AWS configuration not provided")
}

// If multiple accounts are passed.
if len(viper.Get("aws").([]interface{})) > 1 {
logger.Fatal(ctx, "Multiple AWS accounts are not supported at the moment")
}
}

func run(cmd *cobra.Command, args []string) error {
logger, err := logging.NewGoLoggerBuilder().
Debug(viper.GetBool("verbose")).
Expand Down Expand Up @@ -111,20 +163,9 @@ func run(cmd *cobra.Command, args []string) error {
logger.Fatal(cmd.Context(), "parsing rate: %v", err)
}

// Flag overrides config
// Selecting test passed in the Flag
if len(viper.GetStringSlice("test-names")) > 0 {
viper.Set("tests", map[string]interface{}{})
tests := viper.GetStringSlice("test-names")
for _, t := range tests {
viper.Set(fmt.Sprintf("tests.%s", t), map[string]interface{}{})
}
}
configTests()

// If no Flag or Config is passed all test should run
if len(viper.GetStringSlice("test-names")) == 0 && len(viper.GetStringMap("tests")) == 0 {
viper.Set("tests.all", map[string]interface{}{})
}
configAWS(cmd.Context(), logger)

testConfig := types.TestConfiguration{
TestID: viper.GetString("test-id"),
Expand All @@ -133,7 +174,6 @@ func run(cmd *cobra.Command, args []string) error {
Cooldown: time.Duration(viper.GetInt("cooldown")) * time.Second,
Rate: vegetaRate,
Connection: connection,
Viper: viper.Sub("tests"),
Logger: logger,
Ctx: cmd.Context(),
}
Expand Down
9 changes: 9 additions & 0 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ gateway-url: http://localhost:8000 # Gateway URL.
client:
- id: cloud-services # OpenID client identifier.
- secret: "secure-secret" # OpenID client secret.
aws:
- region: "us-west-1"
access-key: "ASD7ASFET65FFGHDFFS"
secret-access-key: "fjhgsadf6#$!@%&/dfghdfgdsdf"
account-id: "123434565665"
- region: "us-west-2"
access-key: "ASD7ASFET65FFGHDFFS"
secret-access-key: "fjhgsadf6#$!@%&/dfghdfgdsdf"
account-id: "123434565665"
duration: 2
cooldown: 10
output-path: "./results"
Expand Down
30 changes: 26 additions & 4 deletions pkg/tests/handlers/clusters.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package handlers

import (
"bytes"
"context"
"fmt"

"github.com/cloud-bulldozer/ocm-api-load/pkg/helpers"
"github.com/cloud-bulldozer/ocm-api-load/pkg/logging"
"github.com/cloud-bulldozer/ocm-api-load/pkg/types"
"github.com/spf13/viper"

v1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
vegeta "github.com/tsenart/vegeta/v12/lib"
Expand All @@ -14,7 +16,7 @@ import (
func TestCreateCluster(options *types.TestOptions) error {

testName := options.TestName
targeter := generateCreateClusterTargeter(options.ID, options.Method, options.Path)
targeter := generateCreateClusterTargeter(options.ID, options.Method, options.Path, options.Context, options.Logger)

for res := range options.Attacker.Attack(targeter, options.Rate, options.Duration, testName) {
options.Encoder.Encode(res)
Expand All @@ -26,14 +28,27 @@ func TestCreateCluster(options *types.TestOptions) error {
// Generates a targeter for the "POST /api/clusters_mgmt/v1/clusters" endpoint
// with monotonic increasing indexes.
// The clusters created are "fake clusters", that is, do not consume any cloud-provider infrastructure.
func generateCreateClusterTargeter(ID, method, url string) vegeta.Targeter {
func generateCreateClusterTargeter(ID, method, url string, ctx context.Context, log logging.Logger) vegeta.Targeter {
idx := 0

// This will take the first 4 characters of the UUID
// Cluster Names must match the following regex:
// ^[a-z]([-a-z0-9]*[a-z0-9])?$
id := ID[:4]

awsCreds := viper.Get("aws").([]interface{})
if len(awsCreds) < 1 {
log.Fatal(ctx, "No aws credentials found")
}

// CCS is used to create fake clusters within the AWS
// environment supplied by the user executing this test.
// Not fully supporting multi account now, so using first accaunt always
ccsRegion := awsCreds[0].(map[interface{}]interface{})["region"].(string)
ccsAccessKey := awsCreds[0].(map[interface{}]interface{})["access-key"].(string)
ccsSecretKey := awsCreds[0].(map[interface{}]interface{})["secret-access-key"].(string)
ccsAccountID := awsCreds[0].(map[interface{}]interface{})["account-id"].(string)

targeter := func(t *vegeta.Target) error {
fakeClusterProps := map[string]string{
"fake_cluster": "true",
Expand All @@ -42,7 +57,14 @@ func generateCreateClusterTargeter(ID, method, url string) vegeta.Targeter {
Name(fmt.Sprintf("perf-%s-%d", id, idx)).
Properties(fakeClusterProps).
MultiAZ(true).
Region(v1.NewCloudRegion().ID(helpers.DefaultAWSRegion)).
Region(v1.NewCloudRegion().ID(ccsRegion)).
CCS(v1.NewCCS().Enabled(true)).
AWS(
v1.NewAWS().
AccessKeyID(ccsAccessKey).
SecretAccessKey(ccsSecretKey).
AccountID(ccsAccountID),
).
Build()
if err != nil {
return err
Expand Down
17 changes: 11 additions & 6 deletions pkg/tests/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import (

func Run(tc types.TestConfiguration) error {
logger := tc.Logger
tests_conf := viper.Sub("tests")
for i, t := range tests {
// Check if the test is set to run
if !tc.Viper.InConfig(t.TestName) && !tc.Viper.InConfig("all") {
if !tests_conf.InConfig(t.TestName) && !tests_conf.InConfig("all") {
continue
}

Expand Down Expand Up @@ -43,21 +44,25 @@ func Run(tc types.TestConfiguration) error {
t.Context = tc.Ctx

// Create the vegeta rate with the config values
if viper.GetString(fmt.Sprintf("%s.rate", t.TestName)) == "" {
current_test_rate := tests_conf.GetString(fmt.Sprintf("%s.rate", t.TestName))
if current_test_rate == "" {
logger.Info(tc.Ctx, "no specific rate for test %s. Using default", t.TestName)
t.Rate = tc.Rate
} else {
r, err := helpers.ParseRate(viper.GetString(fmt.Sprintf("%s.rate", t.TestName)))
r, err := helpers.ParseRate(current_test_rate)
if err != nil {
logger.Warn(tc.Ctx, "error parsing rate for test %s: %s. Using default", t.TestName, fmt.Sprintf("%s.rate", t.TestName))
logger.Warn(tc.Ctx,
"error parsing rate for test %s: %s. Using default",
t.TestName,
current_test_rate)
t.Rate = tc.Rate
} else {
t.Rate = r
}
}

// Check for an override on the test duration
dur := viper.GetInt(fmt.Sprintf("%s.duration", t.TestName))
dur := tests_conf.GetInt(fmt.Sprintf("%s.duration", t.TestName))
if dur == 0 {
// Using default
t.Duration = tc.Duration
Expand All @@ -81,7 +86,7 @@ func Run(tc types.TestConfiguration) error {
return err
}

if i+1 < len(tc.Viper.AllSettings()) {
if i+1 < len(tests_conf.AllSettings()) {
logger.Info(tc.Ctx, "Cooling down for next test for: %v s", tc.Cooldown.Seconds())
time.Sleep(tc.Cooldown)
}
Expand Down
2 changes: 0 additions & 2 deletions pkg/types/test_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (

"github.com/cloud-bulldozer/ocm-api-load/pkg/logging"
sdk "github.com/openshift-online/ocm-sdk-go"
"github.com/spf13/viper"
vegeta "github.com/tsenart/vegeta/v12/lib"
)

Expand All @@ -18,7 +17,6 @@ type TestConfiguration struct {
Cooldown time.Duration
Rate vegeta.Rate
Connection *sdk.Connection
Viper *viper.Viper
Logger logging.Logger
Ctx context.Context
}

0 comments on commit 1c06b20

Please sign in to comment.