Skip to content
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
- run: go mod tidy
- name: Lint
run: |
# Re make protobufs, overwriting any formatting.
# Re generate auto-generated code.
PATH="$HOME/bin:$PATH" make proto
# Check if original code changed due to formatting.
git diff --exit-code
Expand Down
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ build-with-docker: FORCE
# Linter
#########################

lint: check-metrics-doc lint-proto FORCE
lint: check-metrics-doc check-sample-tree lint-proto FORCE
@echo "Running Go Linters..."
golangci-lint run --color=always --new-from-rev=main --timeout=4m
scripts/lint.sh $(go_cmd)
Expand All @@ -367,6 +367,12 @@ generate-metrics-doc: FORCE
check-metrics-doc: FORCE
scripts/metrics_doc.sh check

generate-sample-tree: build FORCE
$(PYTHON_CMD) scripts/loadgen_artifacts_doc.py generate $(project_path)

check-sample-tree: build FORCE
$(PYTHON_CMD) scripts/loadgen_artifacts_doc.py check $(project_path)

# https://www.gnu.org/software/make/manual/html_node/Force-Targets.html
# If a rule has no prerequisites or recipe, and the target of the rule is a nonexistent file,
# then make imagines this target to have been updated whenever its rule is run.
Expand Down
199 changes: 199 additions & 0 deletions docs/loadgen-artifacts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
<!--
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
-->
# Load Generator Artifacts

The load generator can create all the cryptographic materials and configuration artifacts needed for an experiment.
These artifacts include:

- Certificate authorities (CA) and TLS certificates
- MSP (Membership Service Provider) configurations
- Orderer and peer organization credentials
- Genesis block and channel configuration

## Generating Artifacts

The path references in the [sample configuration files](../cmd/config/samples) point to artifacts generated using this tool.

To generate artifacts using the [loadgen sample configuration](../cmd/config/samples/loadgen.yaml):

```bash
loadgen make-artifacts -c ./cmd/config/samples/loadgen.yaml
```

This command outputs artifacts to `/root/artifacts` (as specified in the sample configuration).

## Output Structure

The generated directory structure contains all necessary cryptographic materials organized by organization type:

<!-- TREE MARKER START -->
```
.
├── arma.pb.bin
├── config-block.pb.bin
├── ordererOrganizations/orderer-org-0
│ ├── ca
│ │ ├── orderer-org-0-CA-cert.pem
│ │ └── priv_sk
│ ├── tlsca
│ │ ├── priv_sk
│ │ └── tlsorderer-org-0-CA-cert.pem
│ ├── msp
│ │ ├── admincerts/Admin@orderer-org-0.com-cert.pem
│ │ ├── cacerts/orderer-org-0-CA-cert.pem
│ │ ├── knowncerts
│ │ │ ├── Admin@orderer-org-0.com-cert.pem
│ │ │ ├── client@orderer-org-0.com-cert.pem
│ │ │ ├── consenter-org-0-cert.pem
│ │ │ └── orderer-0-org-0-cert.pem
│ │ └── tlscacerts/tlsorderer-org-0-CA-cert.pem
│ ├── orderers
│ │ ├── consenter-org-0
│ │ │ ├── tls
│ │ │ │ ├── ca.crt
│ │ │ │ ├── server.crt
│ │ │ │ └── server.key
│ │ │ └── msp
│ │ │ ├── admincerts/Admin@orderer-org-0.com-cert.pem
│ │ │ ├── cacerts/orderer-org-0-CA-cert.pem
│ │ │ ├── keystore/priv_sk
│ │ │ ├── signcerts/consenter-org-0-cert.pem
│ │ │ └── tlscacerts/tlsorderer-org-0-CA-cert.pem
│ │ └── orderer-0-org-0
│ │ ├── tls
│ │ │ ├── ca.crt
│ │ │ ├── server.crt
│ │ │ └── server.key
│ │ └── msp
│ │ ├── admincerts/Admin@orderer-org-0.com-cert.pem
│ │ ├── cacerts/orderer-org-0-CA-cert.pem
│ │ ├── keystore/priv_sk
│ │ ├── signcerts/orderer-0-org-0-cert.pem
│ │ └── tlscacerts/tlsorderer-org-0-CA-cert.pem
│ └── users
│ ├── Admin@orderer-org-0.com
│ │ ├── tls
│ │ │ ├── ca.crt
│ │ │ ├── client.crt
│ │ │ └── client.key
│ │ └── msp
│ │ ├── admincerts/Admin@orderer-org-0.com-cert.pem
│ │ ├── cacerts/orderer-org-0-CA-cert.pem
│ │ ├── keystore/priv_sk
│ │ ├── signcerts/Admin@orderer-org-0.com-cert.pem
│ │ └── tlscacerts/tlsorderer-org-0-CA-cert.pem
│ └── client@orderer-org-0.com
│ ├── tls
│ │ ├── ca.crt
│ │ ├── client.crt
│ │ └── client.key
│ └── msp
│ ├── admincerts/client@orderer-org-0.com-cert.pem
│ ├── cacerts/orderer-org-0-CA-cert.pem
│ ├── keystore/priv_sk
│ ├── signcerts/client@orderer-org-0.com-cert.pem
│ └── tlscacerts/tlsorderer-org-0-CA-cert.pem
└── peerOrganizations
├── peer-org-0
│ ├── ca
│ │ ├── peer-org-0-CA-cert.pem
│ │ └── priv_sk
│ ├── tlsca
│ │ ├── priv_sk
│ │ └── tlspeer-org-0-CA-cert.pem
│ ├── msp
│ │ ├── admincerts/Admin@peer-org-0.com-cert.pem
│ │ ├── cacerts/peer-org-0-CA-cert.pem
│ │ ├── knowncerts
│ │ │ ├── Admin@peer-org-0.com-cert.pem
│ │ │ ├── client@peer-org-0.com-cert.pem
│ │ │ └── sidecar-peer-org-0-cert.pem
│ │ └── tlscacerts/tlspeer-org-0-CA-cert.pem
│ ├── peers/sidecar-peer-org-0
│ │ ├── tls
│ │ │ ├── ca.crt
│ │ │ ├── server.crt
│ │ │ └── server.key
│ │ └── msp
│ │ ├── admincerts/Admin@peer-org-0.com-cert.pem
│ │ ├── cacerts/peer-org-0-CA-cert.pem
│ │ ├── keystore/priv_sk
│ │ ├── signcerts/sidecar-peer-org-0-cert.pem
│ │ └── tlscacerts/tlspeer-org-0-CA-cert.pem
│ └── users
│ ├── Admin@peer-org-0.com
│ │ ├── tls
│ │ │ ├── ca.crt
│ │ │ ├── client.crt
│ │ │ └── client.key
│ │ └── msp
│ │ ├── admincerts/Admin@peer-org-0.com-cert.pem
│ │ ├── cacerts/peer-org-0-CA-cert.pem
│ │ ├── keystore/priv_sk
│ │ ├── signcerts/Admin@peer-org-0.com-cert.pem
│ │ └── tlscacerts/tlspeer-org-0-CA-cert.pem
│ └── client@peer-org-0.com
│ ├── tls
│ │ ├── ca.crt
│ │ ├── client.crt
│ │ └── client.key
│ └── msp
│ ├── admincerts/client@peer-org-0.com-cert.pem
│ ├── cacerts/peer-org-0-CA-cert.pem
│ ├── keystore/priv_sk
│ ├── signcerts/client@peer-org-0.com-cert.pem
│ └── tlscacerts/tlspeer-org-0-CA-cert.pem
└── peer-org-1
├── ca
│ ├── peer-org-1-CA-cert.pem
│ └── priv_sk
├── tlsca
│ ├── priv_sk
│ └── tlspeer-org-1-CA-cert.pem
├── msp
│ ├── admincerts/Admin@peer-org-1.com-cert.pem
│ ├── cacerts/peer-org-1-CA-cert.pem
│ ├── knowncerts
│ │ ├── Admin@peer-org-1.com-cert.pem
│ │ ├── client@peer-org-1.com-cert.pem
│ │ └── sidecar-peer-org-1-cert.pem
│ └── tlscacerts/tlspeer-org-1-CA-cert.pem
├── peers/sidecar-peer-org-1
│ ├── tls
│ │ ├── ca.crt
│ │ ├── server.crt
│ │ └── server.key
│ └── msp
│ ├── admincerts/Admin@peer-org-1.com-cert.pem
│ ├── cacerts/peer-org-1-CA-cert.pem
│ ├── keystore/priv_sk
│ ├── signcerts/sidecar-peer-org-1-cert.pem
│ └── tlscacerts/tlspeer-org-1-CA-cert.pem
└── users
├── Admin@peer-org-1.com
│ ├── tls
│ │ ├── ca.crt
│ │ ├── client.crt
│ │ └── client.key
│ └── msp
│ ├── admincerts/Admin@peer-org-1.com-cert.pem
│ ├── cacerts/peer-org-1-CA-cert.pem
│ ├── keystore/priv_sk
│ ├── signcerts/Admin@peer-org-1.com-cert.pem
│ └── tlscacerts/tlspeer-org-1-CA-cert.pem
└── client@peer-org-1.com
├── tls
│ ├── ca.crt
│ ├── client.crt
│ └── client.key
└── msp
├── admincerts/client@peer-org-1.com-cert.pem
├── cacerts/peer-org-1-CA-cert.pem
├── keystore/priv_sk
├── signcerts/client@peer-org-1.com-cert.pem
└── tlscacerts/tlspeer-org-1-CA-cert.pem
```
<!-- TREE MARKER END -->
93 changes: 93 additions & 0 deletions scripts/loadgen_artifacts_doc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/usr/bin/env python3

# Copyright IBM Corp All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0

import json
import os
import subprocess
import sys
import tempfile
from pathlib import Path

start_marker = "<!-- TREE MARKER START -->"
end_marker = "<!-- TREE MARKER END -->"
directory_order = ["ca", "tlsca", "tls", "msp", "orderers", "peers", "users"]


def main():
if len(sys.argv) < 3:
sys.exit("Usage: loadgen_artifacts_doc.py <mode> <project_path>")

mode, project_path = sys.argv[1], Path(sys.argv[2]).resolve()

tree_output = make_tree(
bin_file=project_path / "bin" / "loadgen",
config_file=project_path / "cmd" / "config" / "samples" / "loadgen.yaml",
)

doc_file = project_path / "docs" / "loadgen-artifacts.md"
doc_content = doc_file.read_text()

start = doc_content.find(start_marker) + len(start_marker)
end = doc_content.find(end_marker)
new_content = f"{doc_content[:start]}\n```\n{tree_output}\n```\n{doc_content[end:]}"

if mode == "check":
if new_content != doc_content:
sys.exit("✗ Documentation is out of date. Run 'make generate-sample-tree' to update it.")
else:
doc_file.write_text(new_content)
print(f"✓ Successfully updated {doc_file}")


def make_tree(bin_file, config_file):
with tempfile.TemporaryDirectory() as tmp_dir_name:
# Generate artifacts and get the tree.
subprocess.run(
[str(bin_file), "make-artifacts", "-c", str(config_file)],
env={**os.environ, "SC_LOADGEN_LOAD_PROFILE_POLICY_ARTIFACTS_PATH": tmp_dir_name},
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True,
)
result = subprocess.run(["tree", "-J", "."], cwd=tmp_dir_name, capture_output=True, text=True, check=True)

# Format the tree.
nodes = json.loads(result.stdout)
# The first node is the root and the second is a summary report.
root_node = nodes[0]
return "\n".join(format_tree(root_node))


def format_tree(node: dict):
"""Format tree with collapsed single-child paths."""

name, sub_nodes = node.get("name", ""), node.get("contents", [])

# Collapse single-child chains.
while len(sub_nodes) == 1:
name = str(os.path.join(name, sub_nodes[0].get("name", "")))
sub_nodes = sub_nodes[0].get("contents", [])

yield name

child_trees = map(format_tree, sorted(sub_nodes, key=node_key))
for i, (first_line, *more_lines) in enumerate(child_trees):
is_last_child = i == len(sub_nodes) - 1
# If there are more children, we add a 3 way connector, then continue the thread until the next children.
# For the last children, we use a 2 way connector, and only add the indentation.
children_conn = "├── " if not is_last_child else "└── "
thread_prefix = "│ " if not is_last_child else " "
yield children_conn + first_line
yield from (thread_prefix + l for l in more_lines)


def node_key(node: dict) -> tuple[int, str]:
name = node.get("name")
if name not in directory_order:
return 1000, name
return directory_order.index(name), name


if __name__ == "__main__":
main()
Loading