forked from hyperledger/firefly-perf-cli
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New run Command with Test DSL, Graceful Shutdown, HTTP Server and Pro…
…metheus Metrics, and Sender Support (hyperledger#26) * first attempt at new run command Signed-off-by: hfuss <[email protected]> * command working Signed-off-by: hfuss <[email protected]> * run multiple instances with nohup tested Signed-off-by: hfuss <[email protected]> * fixing instance names in prep.sh Signed-off-by: hfuss <[email protected]> * docker image and k8s dashboard Signed-off-by: hfuss <[email protected]> * somehow missed an import Signed-off-by: hfuss <[email protected]> * Daemon Mode (#1) * Daemon Mode Signed-off-by: hfuss <[email protected]> * finished daemon server; testing now Signed-off-by: hfuss <[email protected]> * fixed graceful shutdown; fixed /status Signed-off-by: hfuss <[email protected]> * more robust stack support Signed-off-by: hfuss <[email protected]> * ensuring docker builds are k8s compatible Signed-off-by: hfuss <[email protected]> * cleaing up code, shut down enhancements, always running server for metrics scraping Signed-off-by: hfuss <[email protected]> * forgot to commit new server package Signed-off-by: hfuss <[email protected]> * file header Signed-off-by: hfuss <[email protected]> * removing unused isdaemon method Signed-off-by: hfuss <[email protected]> * combining deliquent action w/ graceful shutdown Signed-off-by: hfuss <[email protected]> * Requiring Sender DID (#2) * Requiring Sender DID Signed-off-by: hfuss <[email protected]> * tested / debugged sender support Signed-off-by: hfuss <[email protected]> * histogram for perf test duration Signed-off-by: hfuss <[email protected]> * fix Signed-off-by: hfuss <[email protected]> * recipient and recipientaddress are optional Signed-off-by: hfuss <[email protected]> * registering prom metrics Signed-off-by: hfuss <[email protected]> * simplifying perf runner shutdown with cancelling ctx Signed-off-by: hfuss <[email protected]> * timing out in main loop in the event all workers stop Signed-off-by: hfuss <[email protected]> * private messages only receive two confirmations in a multi-member network (multi-receiver not supported by perf tests yet) Signed-off-by: hfuss <[email protected]> * spacing Signed-off-by: hfuss <[email protected]> * Starting subscriptions on connect Signed-off-by: hfuss <[email protected]> * more logging Signed-off-by: hfuss <[email protected]> * fixing missed merge conflict Signed-off-by: hfuss <[email protected]> * PR feedback Signed-off-by: hfuss <[email protected]> * refactoring test names to use enums Signed-off-by: hfuss <[email protected]> * sender support for prep.sh Signed-off-by: hfuss <[email protected]> * including ldflags in make install; ensuring getLogs gets all logs Signed-off-by: hfuss <[email protected]> * updating examples and outputting instances.yaml Signed-off-by: hfuss <[email protected]> * need to close wsconns on graceful shutdown to avoid heartbeat noise during shutdown Signed-off-by: hfuss <[email protected]> * Long run config Signed-off-by: Peter Broadhurst <[email protected]> * Typo Signed-off-by: Peter Broadhurst <[email protected]> * Add check for unknown test and fix prep.sh Signed-off-by: Peter Broadhurst <[email protected]> * 5m -> 500h Signed-off-by: Peter Broadhurst <[email protected]> * Add recipient Signed-off-by: Peter Broadhurst <[email protected]> * simplifying the sender / recipient inputs Signed-off-by: hfuss <[email protected]> * fixing stack parsing Signed-off-by: hfuss <[email protected]> * updating chart example values Signed-off-by: hfuss <[email protected]> Co-authored-by: Peter Broadhurst <[email protected]>
- Loading branch information
1 parent
bba8ce6
commit b7857b1
Showing
28 changed files
with
2,818 additions
and
298 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
.github/ | ||
hack/ | ||
.gitignore | ||
.goreleaser.yml | ||
CODEOWNERS | ||
main | ||
.DS_Store | ||
ffperf/ffperf | ||
ffperf.log | ||
.vscode | ||
dist/ | ||
*.iml | ||
.idea/ | ||
*.md | ||
grafanaDashboard.json | ||
config/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
ARG BUILD_VERSION=canary | ||
|
||
FROM golang:1.17-alpine3.15 as builder | ||
|
||
RUN apk add make gcc build-base curl git | ||
WORKDIR /firefly-perf-cli | ||
ADD go.mod go.sum ./ | ||
RUN go mod download | ||
ADD . . | ||
RUN make VERSION=$BUILD_VERSION build | ||
|
||
FROM alpine:3.15 as final | ||
WORKDIR /firefly-perf-cli | ||
COPY --from=builder /firefly-perf-cli/ffperf/ffperf ./ffperf | ||
RUN ln -s /firefly-perf-cli/ffperf /usr/bin/ffperf | ||
ENTRYPOINT ["ffperf", "run"] | ||
CMD ["--help"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
// Copyright © 2022 Kaleido, Inc. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
// 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 cmd | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"io/ioutil" | ||
"path" | ||
|
||
"github.com/hyperledger/firefly-perf-cli/internal/conf" | ||
"github.com/hyperledger/firefly-perf-cli/internal/perf" | ||
"github.com/hyperledger/firefly-perf-cli/internal/server" | ||
"github.com/hyperledger/firefly-perf-cli/internal/types" | ||
"github.com/hyperledger/firefly/pkg/fftypes" | ||
"github.com/pkg/errors" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/spf13/cobra" | ||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
var configFilePath string | ||
var instanceName string | ||
var instanceIndex int | ||
var daemonOverride bool | ||
var deliquentAction string | ||
|
||
var httpServer *server.HttpServer | ||
var perfRunner perf.PerfRunner | ||
|
||
// runCmd represents the run command | ||
var runCmd = &cobra.Command{ | ||
Use: "run", | ||
Short: "Executes a instance within a performance test suite to generate synthetic load across multiple FireFly nodes within a network", | ||
Long: GetFireflyAsciiArt() + ` | ||
Executes a instance within a performance test suite to generate synthetic load across multiple FireFly nodes within a network | ||
`, | ||
PreRunE: func(cmd *cobra.Command, args []string) error { | ||
config, err := loadConfig(configFilePath) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if !config.Daemon { | ||
config.Daemon = daemonOverride | ||
} | ||
|
||
if instanceName != "" && instanceIndex != -1 { | ||
log.Warn("both the \"instance-name\" and \"instance-index\" flags were provided, using \"instance-name\"") | ||
} | ||
|
||
instance, err := selectInstance(config) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
runnerConfig, err := generateRunnerConfigFromInstance(instance, config) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
perfRunner = perf.New(runnerConfig) | ||
httpServer = server.NewHttpServer() | ||
|
||
return nil | ||
}, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
err := perfRunner.Init() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
go httpServer.Run() | ||
return perfRunner.Start() | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(runCmd) | ||
|
||
runCmd.Flags().StringVarP(&configFilePath, "config", "c", "", "Path to performance config that describes the network and test instances") | ||
runCmd.Flags().StringVarP(&instanceName, "instance-name", "n", "", "Instance within performance config to run against the network") | ||
runCmd.Flags().IntVarP(&instanceIndex, "instance-idx", "i", -1, "Index of the instance within performance config to run against the network") | ||
runCmd.Flags().BoolVarP(&daemonOverride, "daemon", "d", false, "Run in long-lived, daemon mode. Any provided test length is ignored.") | ||
runCmd.Flags().StringVarP(&deliquentAction, "delinquent", "", "exit", "Action to take when delinquent messages are detected. Valid options: [exit log]") | ||
|
||
runCmd.MarkFlagRequired("config") | ||
} | ||
|
||
func loadConfig(filename string) (*conf.PerformanceTestConfig, error) { | ||
if d, err := ioutil.ReadFile(filename); err != nil { | ||
return nil, err | ||
} else { | ||
var config *conf.PerformanceTestConfig | ||
var err error | ||
if path.Ext(filename) == ".yaml" || path.Ext(filename) == ".yml" { | ||
err = yaml.Unmarshal(d, &config) | ||
} else { | ||
err = json.Unmarshal(d, &config) | ||
} | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
return config, nil | ||
} | ||
} | ||
|
||
func selectInstance(config *conf.PerformanceTestConfig) (*conf.InstanceConfig, error) { | ||
if instanceName != "" { | ||
for _, i := range config.Instances { | ||
if i.Name == instanceName { | ||
return &i, nil | ||
} | ||
} | ||
return nil, errors.Errorf("did not find instance named \"%s\" within the provided config", instanceName) | ||
} else if instanceIndex != -1 { | ||
if instanceIndex >= len(config.Instances) || instanceIndex < 0 { | ||
return nil, errors.Errorf("provided instance index \"%d\" is outside of the range of instances within the provided config", instanceIndex) | ||
} | ||
return &config.Instances[instanceIndex], nil | ||
} | ||
|
||
return nil, errors.Errorf("please set either the \"instance-name\" or \"instance-index\" ") | ||
} | ||
|
||
func generateRunnerConfigFromInstance(instance *conf.InstanceConfig, perfConfig *conf.PerformanceTestConfig) (*conf.PerfRunnerConfig, error) { | ||
runnerConfig := &conf.PerfRunnerConfig{ | ||
Tests: instance.Tests, | ||
} | ||
|
||
runnerConfig.StackJSONPath = perfConfig.StackJSONPath | ||
stack, stackErr := readStackJSON(runnerConfig.StackJSONPath) | ||
if stackErr != nil { | ||
return nil, stackErr | ||
} | ||
runnerConfig.NodeURLs = make([]string, len(stack.Members)) | ||
for i, member := range stack.Members { | ||
if member.FireflyHostname == "" { | ||
member.FireflyHostname = "localhost" | ||
} | ||
scheme := "http" | ||
if member.UseHTTPS { | ||
scheme = "https" | ||
} | ||
|
||
runnerConfig.NodeURLs[i] = fmt.Sprintf("%s://%s:%v", scheme, member.FireflyHostname, member.ExposedFireflyPort) | ||
} | ||
|
||
runnerConfig.MessageOptions = instance.MessageOptions | ||
runnerConfig.TokenOptions = instance.TokenOptions | ||
runnerConfig.ContractOptions = instance.ContractOptions | ||
runnerConfig.Workers = instance.Workers | ||
runnerConfig.Length = instance.Length | ||
runnerConfig.WebSocket = perfConfig.WSConfig | ||
runnerConfig.Daemon = perfConfig.Daemon | ||
runnerConfig.DelinquentAction = deliquentAction | ||
|
||
runnerConfig.SenderURL = runnerConfig.NodeURLs[instance.Sender] | ||
if instance.Recipient != nil { | ||
runnerConfig.RecipientOrg = fmt.Sprintf("did:firefly:org/%s", stack.Members[*instance.Recipient].OrgName) | ||
runnerConfig.RecipientAddress = stack.Members[*instance.Recipient].Address | ||
} | ||
|
||
err := validateConfig(*runnerConfig) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return runnerConfig, nil | ||
} | ||
|
||
func validateConfig(cfg conf.PerfRunnerConfig) error { | ||
if cfg.TokenOptions.TokenType != "" && cfg.TokenOptions.TokenType != fftypes.TokenTypeFungible.String() && cfg.TokenOptions.TokenType != fftypes.TokenTypeNonFungible.String() { | ||
return fmt.Errorf("invalid token type. Choose from [%s %s]", fftypes.TokenTypeFungible.String(), fftypes.TokenTypeNonFungible.String()) | ||
} | ||
return nil | ||
} | ||
|
||
func readStackJSON(filename string) (*types.Stack, error) { | ||
if d, err := ioutil.ReadFile(filename); err != nil { | ||
return nil, err | ||
} else { | ||
var stack *types.Stack | ||
if err := json.Unmarshal(d, &stack); err != nil { | ||
return nil, err | ||
} | ||
return stack, nil | ||
} | ||
} |
Oops, something went wrong.