diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8fc7c610..2d796228 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2021-2022, The OTNS Authors. +# Copyright (c) 2021-2024, The OTNS Authors. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -29,12 +29,12 @@ updates: - package-ecosystem: "gitsubmodule" directory: "/" schedule: - interval: "weekly" + interval: "monthly" allow: - - dependency-name: "ot-rfsim" + - dependency-name: "openthread" commit-message: prefix: "submodule" rebase-strategy: "disabled" open-pull-requests-limit: 1 assignees: - - "EskoDijk" + - "jwhui" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 25fd4ebc..1b52e219 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,9 +27,7 @@ name: Build on: - push: - branches-ignore: - - 'dependabot/**' + workflow_dispatch: pull_request: branches: - 'main' @@ -49,10 +47,10 @@ jobs: strategy: fail-fast: false matrix: - go: [ 1.18, 1.22 ] + go: [ '1.18', '1.20', '1.22' ] os: [ ubuntu-22.04, macos-13, macos-14 ] steps: - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} - uses: actions/checkout@v3 diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index 1a168637..1df7b03a 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -49,11 +49,11 @@ jobs: strategy: fail-fast: false matrix: - go: [1.18] + go: [1.22] python-version: ['3.10'] os: [ubuntu-22.04] steps: - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} - uses: actions/setup-python@v5 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 53fbf9af..97842b3c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2020-2023, The OTNS Authors. +# Copyright (c) 2020-2024, The OTNS Authors. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -56,7 +56,7 @@ jobs: submodules: recursive fetch-depth: 0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Prepare id: prepare run: | diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 871960bf..39fdd468 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -27,9 +27,7 @@ name: Lint on: - push: - branches-ignore: - - 'dependabot/**' + workflow_dispatch: pull_request: branches: - 'main' @@ -49,9 +47,9 @@ jobs: env: HOMEBREW_NO_AUTO_UPDATE: 1 steps: - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: - go-version: 1.18 + go-version: '1.22' - uses: actions/checkout@v3 - name: Check pretty run: | diff --git a/.github/workflows/stress.yml b/.github/workflows/stress.yml index 0f97340f..6a91083e 100644 --- a/.github/workflows/stress.yml +++ b/.github/workflows/stress.yml @@ -27,9 +27,7 @@ name: Stress on: - push: - branches-ignore: - - 'dependabot/**' + workflow_dispatch: pull_request: branches: - 'main' @@ -49,14 +47,14 @@ jobs: fail-fast: false matrix: python-version: ['3.10'] - go-version: [1.18] + go-version: ['1.22'] suite: ["network-forming", "commissioning", "connectivity", "network-latency", "multicast-performance", "otns-performance", "network-limits"] runs-on: ubuntu-22.04 timeout-minutes: 120 env: HOMEBREW_NO_AUTO_UPDATE: 1 steps: - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: go-version: ${{ matrix.go-version }} - name: Set up Python diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 64ef17d8..4c93ddf5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,9 +27,7 @@ name: Test on: - push: - branches-ignore: - - 'dependabot/**' + workflow_dispatch: pull_request: branches: - 'main' @@ -54,9 +52,9 @@ jobs: env: HOMEBREW_NO_AUTO_UPDATE: 1 steps: - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: - go-version: 1.18 + go-version: '1.22' - uses: actions/checkout@v3 - name: Test run: | @@ -76,20 +74,20 @@ jobs: env: HOMEBREW_NO_AUTO_UPDATE: 1 steps: - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: - go-version: "1.20" + go-version: '1.22' - name: Set up Python uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - uses: actions/checkout@v3 - - name: Test multiple OT-versions - run: | - ./script/test py-ver-unittests - name: Test single OT-version run: | ./script/test py-unittests + - name: Test multiple OT-versions + run: | + ./script/test py-ver-unittests py-examples: name: Examples (${{ matrix.os }}) @@ -103,9 +101,9 @@ jobs: env: HOMEBREW_NO_AUTO_UPDATE: 1 steps: - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: - go-version: "1.20" + go-version: '1.22' - name: Set up Python uses: actions/setup-python@v5 with: diff --git a/.golangci.yml b/.golangci.yml index a9a2a8fe..f56cbb1c 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,3 +1,3 @@ run: skip-files: - - "web/site/bindata.go" + - "web/site/bindata.go" \ No newline at end of file diff --git a/GUIDE.md b/GUIDE.md index 8a336b2a..dc50ac20 100644 --- a/GUIDE.md +++ b/GUIDE.md @@ -5,7 +5,7 @@ This guide covers the installation of Go, installation of OTNS, use of the OTNS OTNS requires [Go 1.18 or higher](https://golang.org/dl/) to build: - - Install Go from https://golang.org/dl/ + - Install Go from https://golang.org/dl/ or via a package manager (in this case check the Go version is high enough). - Add `$(go env GOPATH)/bin` (normally `$HOME/go/bin`) to `$PATH`. ## Get OTNS code @@ -17,19 +17,21 @@ cd otns ## Automated installation -An automated way to install dependencies, OTNS and all OT nodes is the following command: +An automated way to install dependencies, OTNS and all OT nodes, and test the result, is the following command: ```bash -./script/test build_openthread_versions +./script/test go-tests ``` -Alternatively the extensive unit tests can be run also with the following command: +Alternatively the more extensive Python unit tests can be run also with the following command: ```bash ./script/test py-unittests ``` -However, this can take a long time (5-10 minutes). +However, this can take a long time (5-10 minutes). Running any Python (`py-*`) tests will set up a Python 3 virtual +environment locally in the `.venv-otns` directory. This virtual environment must also be active when manually running +any OTNS Python scripts. ## Manual step-by-step installation @@ -171,7 +173,8 @@ See [OTNS CLI Reference](cli/README.md). ## OTNS Python Scripting [pyOTNS](pylibs/otns) library provides utilities to create and manage simulations through OTNS CLI. It is installed in a -Python 3 virtual environment `.venv-otns`. +Python 3 virtual environment `.venv-otns` by the `./script/install` script. The `./script/test` script also calls this +install script when needed as part of setup. ### Python Scripting Documentation diff --git a/cli/ast.go b/cli/ast.go index 31243ba6..8b525a9e 100644 --- a/cli/ast.go +++ b/cli/ast.go @@ -275,9 +275,9 @@ type ScanCmd struct { // noinspection GoVetStructTag type SpeedCmd struct { - Cmd struct{} `"speed"` //nolint - Max *MaxSpeedFlag `( @@` //nolint - Speed *float64 `| [ (@Int|@Float) ] )` //nolint + Cmd struct{} `"speed"` //nolint + Max *MaxSpeedFlag `[ ( @@` //nolint + Speed *float64 `| (@Int|@Float) ) ]` //nolint } // noinspection GoVetStructTag diff --git a/etc/cli-scripts/ot-script-example.cli b/etc/cli-scripts/ot-script-example.cli deleted file mode 100644 index e59114c6..00000000 --- a/etc/cli-scripts/ot-script-example.cli +++ /dev/null @@ -1,20 +0,0 @@ -# -# Example OT node CLI script, which can be passed to otns using the -ot-script parameter. -# - -# Basic require parameters -networkname Test\ Network -panid 0x1234 -channel 15 -networkkey 998877665544332211ffeeddccbbaa00 - -# Some extra settings -ccathreshold -80 -txpower 10 -routerselectionjitter 10 - -# Autostart the node -ifconfig up -channel monitor stop -thread start - diff --git a/etc/cli-scripts/ot-script-example.yaml b/etc/cli-scripts/ot-script-example.yaml new file mode 100644 index 00000000..b61af40f --- /dev/null +++ b/etc/cli-scripts/ot-script-example.yaml @@ -0,0 +1,48 @@ +# +# Example OT node CLI script, which can be passed to otns using the -ot-script parameter. +# It's in YAML format. Script comment lines start with '#'. +# TODO: enable using script config in same file with YAML network config. +# + +script: + ftd: | + # Active Dataset parameters. This only works for an FTD (e.g. type 'router' or 'fed'). + # Therefore it's in the 'ftd' script section. + dataset init new + dataset networkname Test\ Network + dataset panid 0x1234 + dataset channel 15 + dataset networkkey 998877665544332211ffeeddccbbaa00 + dataset meshlocalprefix fd00:abba:: + dataset commit active + + # Some extra settings - differ from usual setup. + routerselectionjitter 10 + + mtd: | + # MTD not able to use 'dataset init new'. Therefore, other way of providing active dataset. + networkkey 998877665544332211ffeeddccbbaa00 + panid 0x1234 + channel 15 + + br: | + # BR-specific configuration goes here. There's some spaces at EOL to test script-parsing. + ############# + routerselectionjitter 1 + routerdowngradethreshold 33 + routerupgradethreshold 33 + netdata publish route fc00::/7 s med + bbr enable + srp server enable + br init 1 1 + br enable + + all: | + # Some extra settings - differ from usual setup. These are applied to all node types, + # except for 'raw' added nodes. + ccathreshold -50 + txpower 10 + + # Autostart the node + ifconfig up + thread start diff --git a/etc/docker/environment/Dockerfile b/etc/docker/environment/Dockerfile index d2e86d49..116915b2 100644 --- a/etc/docker/environment/Dockerfile +++ b/etc/docker/environment/Dockerfile @@ -1,4 +1,4 @@ -# Copyright (c) 2022-2023, The OTNS Authors. +# Copyright (c) 2022-2024, The OTNS Authors. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -24,7 +24,7 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -FROM golang:1.18 +FROM golang:1.22 RUN apt-get update && apt-get install -y python3 python3-pip sudo unzip nodejs npm git && rm -rf /var/lib/apt/lists/* diff --git a/etc/docker/playground/Dockerfile b/etc/docker/playground/Dockerfile index a966cee8..82abc0f5 100644 --- a/etc/docker/playground/Dockerfile +++ b/etc/docker/playground/Dockerfile @@ -1,4 +1,4 @@ -# Copyright (c) 2020, The OTNS Authors. +# Copyright (c) 2020-2024, The OTNS Authors. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -25,7 +25,7 @@ # POSSIBILITY OF SUCH DAMAGE. # Stage 0: build OTNS and dependencies -FROM golang:1.18 +FROM golang:1.22 RUN apt-get update RUN apt-get install -y python3 python3-pip unzip @@ -33,13 +33,8 @@ RUN apt-get install -y python3 python3-pip unzip COPY . /otns WORKDIR /otns RUN ./script/install-deps +RUN ./script/test build-openthread-versions RUN ./script/install -WORKDIR /otns/ot-rfsim -RUN ./script/bootstrap -RUN ./script/build_latest -RUN ./script/build_v11 -RUN ./script/build_v12 -RUN ./script/build_v13 RUN strip /go/bin/grpcwebproxy /go/bin/otns diff --git a/go.mod b/go.mod index cf3c7cba..e3e41233 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2023, The OTNS Authors. +// Copyright (c) 2020-2024, The OTNS Authors. // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -29,28 +29,26 @@ module github.com/openthread/ot-ns go 1.18 require ( - github.com/alecthomas/participle v0.5.0 + github.com/alecthomas/participle v0.7.1 github.com/chzyer/readline v1.5.1 github.com/mitchellh/go-wordwrap v1.0.1 github.com/pkg/errors v0.9.1 - github.com/stretchr/testify v1.8.4 - go.uber.org/zap v1.22.0 - golang.org/x/term v0.4.0 - google.golang.org/grpc v1.48.0 - google.golang.org/protobuf v1.27.1 + github.com/stretchr/testify v1.9.0 + go.uber.org/zap v1.27.0 + golang.org/x/term v0.21.0 + google.golang.org/grpc v1.64.0 + google.golang.org/protobuf v1.34.1 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/golang/protobuf v1.5.2 // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.6.0 // indirect - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - golang.org/x/sys v0.4.0 // indirect - golang.org/x/text v0.3.3 // indirect - google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482 // indirect + go.uber.org/multierr v1.10.0 // indirect + golang.org/x/net v0.22.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect ) diff --git a/ot-rfsim/script/bootstrap b/ot-rfsim/script/bootstrap deleted file mode 100755 index 1de50f60..00000000 --- a/ot-rfsim/script/bootstrap +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2017-2024, The OpenThread Authors. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of the copyright holder nor the -# names of its contributors may be used to endorse or promote products -# derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -# Description: -# This file installs all needed dependencies and toolchains needed for -# ot-rfsim compilation and programming. -# - -set -euxo pipefail - -install_packages_apt() -{ - echo 'Installing toolchain dependencies...' - - # apt-get update and install dependencies - apt-get update - apt-get --no-install-recommends install -y g++ lsb-release cmake ninja-build shellcheck -} - -install_packages_opkg() -{ - echo 'opkg not supported currently' && false -} - -install_packages_rpm() -{ - echo 'rpm not supported currently' && false -} - -install_packages_brew() -{ - echo 'Installing toolchain dependencies...' - - # add build tools - brew install cmake ninja shfmt shellcheck - - # check for gcc for simulation - if ! command -v gcc; then - echo 'warning: clang/gcc needed for simulation' - echo 'warning: please install Command Line Tools from https://developer.apple.com/download/more/' - fi -} - -install_packages_source() -{ - echo 'source not supported currently' && false -} - -install_packages() -{ - PM=source - if command -v apt-get; then - PM=apt - elif command -v rpm; then - PM=rpm - elif command -v opkg; then - PM=opkg - elif command -v brew; then - PM=brew - fi - install_packages_$PM -} - -main() -{ - if [ "$EUID" -ne 0 ]; then - echo "Please run as root user, e.g. 'sudo ./script/bootstrap'." && false - fi - install_packages - echo 'bootstrap for ot-rfsim completed successfully.' -} - -main diff --git a/otns_main/otns_main.go b/otns_main/otns_main.go index 7bd09e2a..ad2a3ca1 100644 --- a/otns_main/otns_main.go +++ b/otns_main/otns_main.go @@ -283,9 +283,9 @@ func createSimulation(simId int, ctx *progctx.ProgCtx) (*simulation.Simulation, simcfg.Id = simId if len(args.InitScriptName) > 0 { if args.InitScriptName == "none" { - simcfg.NewNodeConfig.InitScript = []string{} // zero lines of init-script + simcfg.NewNodeScripts = &simulation.YamlScriptConfig{} } else { - simcfg.NewNodeConfig.InitScript, err = simulation.ReadNodeScript(args.InitScriptName) + simcfg.NewNodeScripts, err = simulation.ReadNodeScript(args.InitScriptName) if err != nil { return nil, err } diff --git a/otnstester/OtnsTest.go b/otnstester/OtnsTest.go index 107a3473..c2204017 100644 --- a/otnstester/OtnsTest.go +++ b/otnstester/OtnsTest.go @@ -429,7 +429,7 @@ func NewOtnsTest(t *testing.T) *OtnsTest { }) }() - grpcConn, err := grpc.Dial("localhost:8999", grpc.WithTransportCredentials(insecure.NewCredentials())) + grpcConn, err := grpc.NewClient("localhost:8999", grpc.WithTransportCredentials(insecure.NewCredentials())) ot.ExpectNoError(err) grpcClient := visualize_grpc_pb.NewVisualizeGrpcServiceClient(grpcConn) diff --git a/otoutfilter/OTOutFilter_test.go b/otoutfilter/OTOutFilter_test.go index 50b0b730..7ed36a1c 100644 --- a/otoutfilter/OTOutFilter_test.go +++ b/otoutfilter/OTOutFilter_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2022, The OTNS Authors. +// Copyright (c) 2020-2024, The OTNS Authors. // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -27,7 +27,7 @@ package otoutfilter import ( - "io/ioutil" + "io" "strings" "testing" ) @@ -70,7 +70,7 @@ func TestOTOutFilter(t *testing.T) { "" r := NewOTOutFilter(strings.NewReader(input), "Node<1> - ", nil) - output, err := ioutil.ReadAll(r) + output, err := io.ReadAll(r) if err != nil { t.Fatal(err) } diff --git a/pylibs/case_studies/forced_key_rotation.py b/pylibs/case_studies/forced_key_rotation.py index 50f6a980..d1556d3e 100755 --- a/pylibs/case_studies/forced_key_rotation.py +++ b/pylibs/case_studies/forced_key_rotation.py @@ -56,6 +56,8 @@ def main(): ns.ping(1,2) ns.go(10) + # run some time to catch MLE messages from node 2 - should reflect same Key Index. + ns.go(150) ns.web_display() if __name__ == '__main__': diff --git a/pylibs/otns/cli/OTNS.py b/pylibs/otns/cli/OTNS.py index c369e954..783bad51 100644 --- a/pylibs/otns/cli/OTNS.py +++ b/pylibs/otns/cli/OTNS.py @@ -937,6 +937,37 @@ def set_networkkey(self, nodeid: int, key: str) -> None: """ self.node_cmd(nodeid, f'networkkey {key}') + def config_dataset(self, nodeid: int, channel: int = None, panid: int = None, extpanid: str = None, networkkey: str = None, network_name: str = None, + dataset='active'): + """ + Configure the active/pending dataset + + :param nodeid: target node ID + :param channel: the channel number. + :param panid: the Pan ID. + :param extpanid: the Extended PAN ID. + :param networkkey: the network key (REQUIRED) + :param network_name: the network name + """ + assert dataset in ('active', 'pending'), dataset + + self.node_cmd(nodeid, 'dataset clear') + + if channel is not None: + self.node_cmd(nodeid, f'dataset channel {channel}') + + if panid is not None: + self.node_cmd(nodeid, f'dataset panid 0x{panid:04x}') + + if networkkey is not None: + self.node_cmd(nodeid, f'dataset networkkey {networkkey}') + + if network_name is not None: + network_name = self._escape_whitespace(network_name) + self.node_cmd(nodeid, f'dataset networkname {network_name}') + + self.node_cmd(nodeid, f'dataset commit {dataset}') + def web(self, tab_name: str = "") -> None: """ Open web browser for visualization. diff --git a/pylibs/setup.py b/pylibs/setup.py index 67cffd4c..6d8e90da 100755 --- a/pylibs/setup.py +++ b/pylibs/setup.py @@ -29,7 +29,7 @@ setuptools.setup( name="pyOTNS", - version="2.0.0", + version="2.1.0", author="The OTNS Authors", description="Run OTNS2 OpenThread mesh network simulations from Python code", url="https://github.com/EskoDijk/ot-ns", diff --git a/pylibs/stress_tests/BaseStressTest.py b/pylibs/stress_tests/BaseStressTest.py index e5e7be91..01b69db5 100644 --- a/pylibs/stress_tests/BaseStressTest.py +++ b/pylibs/stress_tests/BaseStressTest.py @@ -66,9 +66,9 @@ def run_wrapper(self: 'BaseStressTest', report=True): class BaseStressTest(object, metaclass=StressTestMetaclass): - def __init__(self, name, headers, web=True, raw=False): + def __init__(self, name, headers, web=True, raw=False, rand_seed=0): self.name = name - self._otns_args = ['-log','info','-logfile','none'] # use ['-log', 'debug'] for more debug messages + self._otns_args = ['-log','info','-logfile','none','-seed',str(rand_seed)] # use ['-log', 'debug'] for more debug messages if raw: self._otns_args.append('-ot-script') self._otns_args.append('none') diff --git a/pylibs/stress_tests/network_limits.py b/pylibs/stress_tests/network_limits.py index 94060532..34c67e84 100755 --- a/pylibs/stress_tests/network_limits.py +++ b/pylibs/stress_tests/network_limits.py @@ -42,11 +42,21 @@ class StressTest(BaseStressTest): SUITE = 'network-limits' + # Time limits for attaching in minutes, per parent-type and child-type. For BR as Parent, + # more time is allowed (as it has more capacity). TIME_LIMIT = { - 'fed': 1, - 'med': 1, - 'sed': 1, - 'ssed': 1, + 'router': { + 'fed': 1, + 'med': 1, + 'sed': 1, + 'ssed': 1, + }, + 'br': { + 'fed': 2, + 'med': 2, + 'sed': 2, + 'ssed': 2, + }, } def __init__(self): @@ -55,27 +65,28 @@ def __init__(self): def run(self): self.ns.speed = 30 # speed is lowered to see the visualization, when run locally. - self.test('fed') - self.test('med') - self.test('sed') - self.test('ssed') + self.test('fed', 'router') + self.test('med', 'router') + self.test('sed', 'router') + self.test('ssed', 'router') # a BR can support more children (compile-time configured) self.test('fed', 'br', CHILDREN_N_BR) self.test('med', 'br', CHILDREN_N_BR) self.test('sed', 'br', CHILDREN_N_BR) - self.test('ssed', 'br', CHILDREN_N_BR) + self.test('ssed','br', CHILDREN_N_BR) - def test(self, child_type: str, parent_type: str = 'router', n_children_max: int = CHILDREN_N): + def test(self, child_type: str, parent_type: str, n_children_max: int = CHILDREN_N): self.reset() self.ns.log = 'debug' - self.ns.watch_default('trace') + #self.ns.watch_default('trace') # can enable trace level to see radio state details self.ns.add(parent_type, PARENT_X, PARENT_Y) self.ns.go(7) - time_limit = StressTest.TIME_LIMIT[child_type] + time_limit = StressTest.TIME_LIMIT[parent_type][child_type] all_children = [] + logging.info(f"Testing '{parent_type}' parent with child type '{child_type}' (N={n_children_max})") for i in range(n_children_max): angle = math.pi * 2 * i / n_children_max @@ -93,11 +104,10 @@ def test(self, child_type: str, parent_type: str = 'router', n_children_max: int if self.ns.get_state(child) == 'child': n_children += 1 if n_children == n_children_max: - logging.info("All %s children has attached successfully within %d minutes.", child_type, i + 1) + logging.info("All %s children attached successfully within %d minutes, with time limit set to %d minutes.", child_type, i + 1, time_limit) break - self.ns.speed = 0.01 - self.ns.go(0.01) # trick to ensure final topology is briefly shown in web UI + self.ns.web_display() if n_children < n_children_max: raise Exception("Not all %s children attached within time limit of %d minutes." % (child_type, time_limit)) diff --git a/pylibs/stress_tests/otns_performance.py b/pylibs/stress_tests/otns_performance.py index 4ff3adbb..1f8e4482 100755 --- a/pylibs/stress_tests/otns_performance.py +++ b/pylibs/stress_tests/otns_performance.py @@ -57,7 +57,8 @@ class OtnsPerformanceStressTest(BaseStressTest): def __init__(self): super(OtnsPerformanceStressTest, self).__init__("OTNS Performance Test", ['Simulation Time', 'Execution Time', 'Speed Up', - 'Alarm Events', 'Radio Events']) + 'Alarm Events', 'Radio Events'], + rand_seed=48392) def run(self): ns = self.ns diff --git a/pylibs/unittests/requirements.txt b/pylibs/unittests/requirements.txt index 4c5c8565..4e262d75 100644 --- a/pylibs/unittests/requirements.txt +++ b/pylibs/unittests/requirements.txt @@ -1,4 +1,4 @@ -grpcio-tools>=1.31.0 -grpcio>=1.31.0 -protobuf==3.15.0 -wheel==0.38.1 +grpcio-tools==1.53.0 +grpcio==1.53.0 +protobuf==4.21.6 +wheel==0.42.0 diff --git a/pylibs/unittests/test_basic.py b/pylibs/unittests/test_basic.py index 86417dd9..5f9a7269 100755 --- a/pylibs/unittests/test_basic.py +++ b/pylibs/unittests/test_basic.py @@ -190,7 +190,6 @@ def testDelNodeAndImmediatelyRecreate(self): ns = self.ns ns.loglevel = 'debug' - ns.watch_default('debug') # add extra detail in all node's logs id = ns.add("router") self.assertTrue(len(ns.nodes()) == 1 and 1 in ns.nodes() and id == 1) self.go(i/100) @@ -351,7 +350,7 @@ def testWithOTNS(self): """ make sure OTNS works in with-statement """ - self.tearDown() + self.ns.close() with OTNS(otns_args=['-log', 'debug']) as ns: self.assertEqual(OTNS.DEFAULT_SIMULATE_SPEED, ns.speed) @@ -663,7 +662,7 @@ def testCmdCommand(self): self.assertEqual(0, len(output)) def testRandomSeedSetting(self): - self.tearDown() + self.ns.close() nodes = range(1,6) # create a new OTNS with 'seed' parameter. @@ -878,6 +877,24 @@ def testSendUdpCoap(self): for a in addrs: self.assertFalse(a.startswith("ff13")) # see Go simulation.SendMcastPrefix + def testLoadOtScript(self): + self.ns.close() + + with OTNS(otns_args=['-ot-script', './etc/cli-scripts/ot-script-example.yaml', '-log', 'debug']) as ns: + self.ns = ns + ns.add('router') + ns.go(10) + ns.add('router') + ns.add('router') + ns.add('med') + ns.add('fed') + ns.go(30) + self.assertFormPartitions(1) + ns.add('br') + ns.add('sed') + ns.go(30) + self.assertFormPartitions(1) + if __name__ == '__main__': unittest.main() diff --git a/pylibs/unittests/test_commissioning.py b/pylibs/unittests/test_commissioning.py index b4a6f8f6..c364905c 100755 --- a/pylibs/unittests/test_commissioning.py +++ b/pylibs/unittests/test_commissioning.py @@ -37,7 +37,7 @@ class CommissioningTests(OTNSTestCase): def setUp(self) -> None: - self.ns = OTNS(otns_args=['-ot-script', 'none', '-log', 'debug']) + self.ns = OTNS(otns_args=['-ot-script', 'none', '-log', 'debug', '-pcap', 'wpan-tap']) self.ns.speed = float('inf') def testRawNoSetup(self): @@ -50,17 +50,30 @@ def testRawNoSetup(self): def testRawSetup(self): ns = self.ns - n1 = ns.add("router", x=0, y=0) - n2 = ns.add("router", x=50, y=0) - n3 = ns.add("router", x=0, y=50) - for id in (n1, n2, n3): - ns.set_network_name(id, "test") - ns.set_panid(id, 0xface) - ns.set_networkkey(id, "00112233445566778899aabbccddeeff") + n1 = ns.add("router") + n2 = ns.add("router") + n3 = ns.add("router") + + # n1 with full dataset becomes Leader. + ns.node_cmd(n1, "dataset init new") + ns.node_cmd(n1, "dataset panid 0xface") + ns.node_cmd(n1, "dataset extpanid dead00beef00cafe") + ns.node_cmd(n1, "dataset networkkey 00112233445566778899aabbccddeeff") + ns.node_cmd(n1, "dataset networkname test") + ns.node_cmd(n1, "dataset channel 15") + ns.node_cmd(n1, "dataset commit active") + ns.ifconfig_up(n1) + ns.thread_start(n1) + + # n2, n3 with partial dataset - if channel not given - will scan channels to find n1. + # This can take some time and may fail even then (FIXME: find cause). + # To prevent this failure, channel is provided here. + for id in (n2, n3): + ns.config_dataset(id, channel=15, panid=0xface, extpanid="dead00beef00cafe", network_name="test", networkkey="00112233445566778899aabbccddeeff") ns.ifconfig_up(id) ns.thread_start(id) - self.go(30) + self.go(300) self.assertFormPartitions(1) def testCommissioning(self): diff --git a/script/common.sh b/script/common.sh index e4ab454c..01e40065 100644 --- a/script/common.sh +++ b/script/common.sh @@ -63,13 +63,7 @@ go_install() get_openthread() { if [[ ! -f ./openthread/script/bootstrap ]]; then - git submodule update --init --recursive --depth 1 - fi -} - -get_openthread_versions() -{ - if [[ ! -f ./openthread/script/bootstrap ]]; then + # --depth 1 is not used here, due to need to build historic commits for OT nodes. git submodule update --init --recursive fi } @@ -109,7 +103,7 @@ build_openthread_br() build_openthread_versions() { - get_openthread_versions + get_openthread install_openthread_buildtools ( cd ot-rfsim diff --git a/script/install-deps b/script/install-deps index d2be3b2d..70127e14 100755 --- a/script/install-deps +++ b/script/install-deps @@ -35,6 +35,7 @@ apt_update_once=0 install_packages() { install_package wget --apt wget --brew wget || true + install_package python3-venv --apt wget --brew wget || true } install_grpcwebproxy() @@ -55,7 +56,7 @@ install_grpcwebproxy() install_python_libs() { activate_python_venv - python3 -m pip install setuptools + python3 -m pip install setuptools wheel } main() diff --git a/script/pack-web b/script/pack-web index 728446b6..85560e61 100755 --- a/script/pack-web +++ b/script/pack-web @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright (c) 2020-2023, The OTNS Authors. +# Copyright (c) 2020-2024, The OTNS Authors. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -33,12 +33,13 @@ main() { readonly sitedir="$OTNSDIR"/web/site - cd "$sitedir" || return 1 - npm install - npm version - npx webpack ./js/visualize.js -o ./static/js/visualize.js - npx webpack ./js/energyViewer.js -o ./static/js/energyViewer.js - npx webpack ./js/statsViewer.js -o ./static/js/statsViewer.js + ( + cd "$sitedir" + npm install + npm version + npx webpack ./js/visualize.js -o ./static/js/visualize.js + npx webpack ./js/energyViewer.js -o ./static/js/energyViewer.js + npx webpack ./js/statsViewer.js -o ./static/js/statsViewer.js go-bindata -pkg web_site -o _bindata.go templates/... static/... head -26 bindata.go >_merge_bindata.go diff --git a/script/utils.sh b/script/utils.sh index f5787ce2..2de0ebf2 100644 --- a/script/utils.sh +++ b/script/utils.sh @@ -111,10 +111,10 @@ install_package() function install_pretty_tools() { if ! installed golangci-lint; then - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "$(go env GOPATH)"/bin v1.50.1 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "$(go env GOPATH)"/bin v1.59.0 fi - install_package shfmt --brew shfmt --snap shfmt + go install mvdan.cc/sh/v3/cmd/shfmt@latest install_package shellcheck --apt shellcheck --brew shellcheck } diff --git a/simulation/node.go b/simulation/node.go index fac66bce..74786e0e 100644 --- a/simulation/node.go +++ b/simulation/node.go @@ -162,6 +162,10 @@ func (node *Node) runScript(cfg []string) error { } for _, cmd := range cfg { + cmd = strings.TrimSpace(cmd) + if len(cmd) == 0 || strings.HasPrefix(cmd, "#") { + continue // skip empty lines and comments + } if node.CommandResult() != nil { return node.CommandResult() } diff --git a/simulation/node_config.go b/simulation/node_config.go index 91c3bee8..27b84995 100644 --- a/simulation/node_config.go +++ b/simulation/node_config.go @@ -47,18 +47,38 @@ const ( versionLatestTag = "v14" ) -// defaultNodeInitScript is an array of commands, sent to a new node by default (unless changed). -var defaultNodeInitScript = []string{ - "networkname " + DefaultNetworkName, - "networkkey " + DefaultNetworkKey, +// defaultFtdInitScript is an array of commands, sent to a new FTD node by default (unless changed). +var defaultFtdInitScript = []string{ + "dataset init new", + fmt.Sprintf("dataset networkname %s", DefaultNetworkName), + fmt.Sprintf("dataset networkkey %s", DefaultNetworkKey), + fmt.Sprintf("dataset panid 0x%x", DefaultPanid), + fmt.Sprintf("dataset channel %d", DefaultChannel), + fmt.Sprintf("dataset extpanid %s", DefaultExtPanid), + fmt.Sprintf("dataset meshlocalprefix %s", DefaultMeshLocalPrefix), + fmt.Sprintf("dataset pskc %s", DefaultPskc), + //"routerselectionjitter 1", // jitter can be set to '1' to speed up network formation for realtime tests. + "dataset commit active", +} + +// defaultMtdInitScript is an array of commands, sent to a new MTD node by default (unless changed). +// because the MTD doesn't support 'dataset init new', an alternative way is needed to configure the +// active dataset. Another alternative (not used here) is 'dataset init tlvs 0e0800000000000100...' with +// the full dataset in hex format. +var defaultMtdInitScript = []string{ + fmt.Sprintf("networkkey %s", DefaultNetworkKey), fmt.Sprintf("panid 0x%x", DefaultPanid), fmt.Sprintf("channel %d", DefaultChannel), - //"routerselectionjitter 1", // jitter can be set to '1' to speed up network formation for realtime tests. + fmt.Sprintf("extpanid %s", DefaultExtPanid), +} + +// defaultAllInitScript is an array of commands, sent to any type of new node (as last script commands). +var defaultAllInitScript = []string{ "ifconfig up", "thread start", } -// defaultBrScript is an array of commands, sent to a new BR by default (unless changed). +// defaultBrScript is an array of additional commands, sent to a new BR by default (unless changed). var defaultBrScript = []string{ "routerselectionjitter 1", // BR wants to become Router early on. "routerdowngradethreshold 33", // BR never wants to downgrade. @@ -141,11 +161,20 @@ func DefaultNodeConfig() NodeConfig { RadioRange: defaultRadioRange, ExecutablePath: "", Restore: false, - InitScript: defaultNodeInitScript, + InitScript: []string{}, RandomSeed: 0, // 0 means not specified, i.e. truly unpredictable. } } +func DefaultNodeScripts() *YamlScriptConfig { + return &YamlScriptConfig{ + Mtd: strings.Join(defaultMtdInitScript, "\n"), + Ftd: strings.Join(defaultFtdInitScript, "\n"), + Br: strings.Join(defaultBrScript, "\n"), + All: strings.Join(defaultAllInitScript, "\n"), + } +} + // NodeConfigFinalize finalizes the configuration for a new Node before it's used to create it. This is not // mandatory to call, but a convenience method for the caller to avoid setting all details itself. func (s *Simulation) NodeConfigFinalize(nodeCfg *NodeConfig) { @@ -166,18 +195,24 @@ func (s *Simulation) NodeConfigFinalize(nodeCfg *NodeConfig) { nodeCfg.RandomSeed = prng.NewNodeRandomSeed() } - // for a BR, do extra init steps to set prefix/routes/etc. - if nodeCfg.IsBorderRouter { - nodeCfg.InitScript = append(nodeCfg.InitScript, defaultBrScript...) - } + // build node init-script + if !nodeCfg.IsRaw { + if nodeCfg.IsBorderRouter { // for a BR, do extra init steps to set prefix/routes/etc. + nodeCfg.InitScript = append(nodeCfg.InitScript, s.cfg.NewNodeScripts.BuildBrScript()...) + } else if nodeCfg.IsMtd { + nodeCfg.InitScript = append(nodeCfg.InitScript, s.cfg.NewNodeScripts.BuildMtdScript()...) + } else { + nodeCfg.InitScript = append(nodeCfg.InitScript, s.cfg.NewNodeScripts.BuildFtdScript()...) + } - // for SSED, do extra CSL init command. - if nodeCfg.Type == SSED { - cslScript := defaultCslScript - if len(nodeCfg.Version) > 0 && nodeCfg.Version <= "v13" { - cslScript = defaultLegacyCslScript // older nodes use different parameter unit + // for SSED, do extra CSL init command. + if nodeCfg.Type == SSED { + cslScript := defaultCslScript + if len(nodeCfg.Version) > 0 && nodeCfg.Version <= "v13" { + cslScript = defaultLegacyCslScript // older nodes use different parameter unit + } + nodeCfg.InitScript = append(nodeCfg.InitScript, cslScript...) } - nodeCfg.InitScript = append(nodeCfg.InitScript, cslScript...) } // for Wifi interferer, run specific script. diff --git a/simulation/nodescript_parser.go b/simulation/nodescript_parser.go index 7c7e43a8..cb48df08 100644 --- a/simulation/nodescript_parser.go +++ b/simulation/nodescript_parser.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022-2023, The OTNS Authors. +// Copyright (c) 2022-2024, The OTNS Authors. // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -28,24 +28,22 @@ package simulation import ( "fmt" - "io/ioutil" - "strings" + "os" + + "gopkg.in/yaml.v3" ) -func ReadNodeScript(fn string) ([]string, error) { - script, err := ioutil.ReadFile(fn) +func ReadNodeScript(fn string) (*YamlScriptConfig, error) { + b, err := os.ReadFile(fn) if err != nil { - err = fmt.Errorf("could not read OT node script file: %s (%w)", fn, err) - return []string{}, err + err = fmt.Errorf("could not load script config file '%s': %v", fn, err) + return nil, err } - linesToFilter := strings.Split(string(script), "\n") - linesFiltered := make([]string, 0) - for _, line := range linesToFilter { - line = strings.TrimSpace(line) - if strings.HasPrefix(line, "#") || strings.HasPrefix(line, "//") || line == "" { - continue - } - linesFiltered = append(linesFiltered, line) + cfgFile := YamlConfigFile{} + err = yaml.Unmarshal(b, &cfgFile) + if err != nil { + err = fmt.Errorf("error in YAML file: %v", err) + return nil, err } - return linesFiltered, nil + return &cfgFile.ScriptConfig, nil } diff --git a/simulation/simulation_config.go b/simulation/simulation_config.go index 3a1b3c45..7af4d166 100644 --- a/simulation/simulation_config.go +++ b/simulation/simulation_config.go @@ -33,16 +33,20 @@ import ( ) const ( - DefaultNetworkName = "OTSIM" - DefaultNetworkKey = "00112233445566778899aabbccddeeff" - DefaultPanid = 0xface - DefaultChannel = 11 + DefaultChannel = 11 + DefaultExtPanid = "dead00beef00cafe" + DefaultMeshLocalPrefix = "fdde:ad00:beef:0::" + DefaultNetworkKey = "00112233445566778899aabbccddeeff" + DefaultNetworkName = "otns" + DefaultPanid = 0xface + DefaultPskc = "3aa55f91ca47d1e4e71a08cb35e91591" ) type Config struct { ExeConfig ExecutableConfig ExeConfigDefault ExecutableConfig NewNodeConfig NodeConfig + NewNodeScripts *YamlScriptConfig Speed float64 ReadOnly bool Realtime bool @@ -64,6 +68,7 @@ func DefaultConfig() *Config { ExeConfig: DefaultExecutableConfig, ExeConfigDefault: DefaultExecutableConfig, NewNodeConfig: DefaultNodeConfig(), + NewNodeScripts: DefaultNodeScripts(), Speed: 1, ReadOnly: false, Realtime: false, diff --git a/simulation/types.go b/simulation/types.go index 4cbf3f78..65ee6ae2 100644 --- a/simulation/types.go +++ b/simulation/types.go @@ -30,6 +30,7 @@ import ( "fmt" "io" "regexp" + "strings" . "github.com/openthread/ot-ns/types" ) @@ -64,10 +65,19 @@ type NodeCounters map[string]int // YamlConfigFile is the complete YAML structure for a config file for load/save. type YamlConfigFile struct { + ScriptConfig YamlScriptConfig `yaml:"script"` NetworkConfig YamlNetworkConfig `yaml:"network"` NodesList []YamlNodeConfig `yaml:"nodes"` } +// YamlScriptConfig defines startup scripts for nodes, depending on node type. +type YamlScriptConfig struct { + Mtd string `yaml:"mtd"` + Ftd string `yaml:"ftd"` + Br string `yaml:"br"` + All string `yaml:"all"` +} + // YamlNetworkConfig is a global network config that can be loaded/saved in YAML. type YamlNetworkConfig struct { Position [3]int `yaml:"pos-shift,flow"` // provides an optional 3D position shift of all nodes. @@ -93,3 +103,18 @@ func (yc *YamlConfigFile) MinNodeId() NodeId { } return m } + +func (ys *YamlScriptConfig) BuildMtdScript() []string { + script := ys.Mtd + "\n" + ys.All + return strings.Split(script, "\n") +} + +func (ys *YamlScriptConfig) BuildFtdScript() []string { + script := ys.Ftd + "\n" + ys.All + return strings.Split(script, "\n") +} + +func (ys *YamlScriptConfig) BuildBrScript() []string { + script := ys.Ftd + "\n" + ys.Br + "\n" + ys.All + return strings.Split(script, "\n") +} diff --git a/types/node_config.go b/types/node_config.go index 7312f3eb..55127d18 100644 --- a/types/node_config.go +++ b/types/node_config.go @@ -43,7 +43,7 @@ type NodeConfig struct { RadioRange int ExecutablePath string // executable full path or "" for auto-determined Restore bool - InitScript []string + InitScript []string // a sequence of CLI commands executed at first startup of node RandomSeed int32 } diff --git a/web/site/bindata.go b/web/site/bindata.go index 003b0c02..a8824138 100644 --- a/web/site/bindata.go +++ b/web/site/bindata.go @@ -1496,65 +1496,63 @@ var _bindata = map[string]func() ([]byte, error){ "static/image/white-shapes/square-dashed-rounded-32.png": static_image_white_shapes_square_dashed_rounded_32_png, "static/image/white-shapes/square-dashed-rounded-48.png": static_image_white_shapes_square_dashed_rounded_48_png, "static/image/white-shapes/square-dashed-rounded-512.png": static_image_white_shapes_square_dashed_rounded_512_png, - "static/image/white-shapes/square-dashed-rounded-64.png": static_image_white_shapes_square_dashed_rounded_64_png, - "static/image/white-shapes/square-ios-app-128.png": static_image_white_shapes_square_ios_app_128_png, - "static/image/white-shapes/square-ios-app-16.png": static_image_white_shapes_square_ios_app_16_png, - "static/image/white-shapes/square-ios-app-24.png": static_image_white_shapes_square_ios_app_24_png, - "static/image/white-shapes/square-ios-app-256.png": static_image_white_shapes_square_ios_app_256_png, - "static/image/white-shapes/square-ios-app-32.png": static_image_white_shapes_square_ios_app_32_png, - "static/image/white-shapes/square-ios-app-48.png": static_image_white_shapes_square_ios_app_48_png, - "static/image/white-shapes/square-ios-app-512.png": static_image_white_shapes_square_ios_app_512_png, - "static/image/white-shapes/square-ios-app-64.png": static_image_white_shapes_square_ios_app_64_png, - "static/image/white-shapes/square-outline-128.png": static_image_white_shapes_square_outline_128_png, - "static/image/white-shapes/square-outline-16.png": static_image_white_shapes_square_outline_16_png, - "static/image/white-shapes/square-outline-24.png": static_image_white_shapes_square_outline_24_png, - "static/image/white-shapes/square-outline-256.png": static_image_white_shapes_square_outline_256_png, - "static/image/white-shapes/square-outline-32.png": static_image_white_shapes_square_outline_32_png, - "static/image/white-shapes/square-outline-48.png": static_image_white_shapes_square_outline_48_png, - "static/image/white-shapes/square-outline-512.png": static_image_white_shapes_square_outline_512_png, - "static/image/white-shapes/square-outline-64.png": static_image_white_shapes_square_outline_64_png, - "static/image/white-shapes/square-rounded-128.png": static_image_white_shapes_square_rounded_128_png, - "static/image/white-shapes/square-rounded-16.png": static_image_white_shapes_square_rounded_16_png, - "static/image/white-shapes/square-rounded-24.png": static_image_white_shapes_square_rounded_24_png, - "static/image/white-shapes/square-rounded-256.png": static_image_white_shapes_square_rounded_256_png, - "static/image/white-shapes/square-rounded-32.png": static_image_white_shapes_square_rounded_32_png, - "static/image/white-shapes/square-rounded-48.png": static_image_white_shapes_square_rounded_48_png, - "static/image/white-shapes/square-rounded-512.png": static_image_white_shapes_square_rounded_512_png, - "static/image/white-shapes/square-rounded-64.png": static_image_white_shapes_square_rounded_64_png, - "static/image/white-shapes/triangle-128.png": static_image_white_shapes_triangle_128_png, - "static/image/white-shapes/triangle-16.png": static_image_white_shapes_triangle_16_png, - "static/image/white-shapes/triangle-24.png": static_image_white_shapes_triangle_24_png, - "static/image/white-shapes/triangle-256.png": static_image_white_shapes_triangle_256_png, - "static/image/white-shapes/triangle-32.png": static_image_white_shapes_triangle_32_png, - "static/image/white-shapes/triangle-48.png": static_image_white_shapes_triangle_48_png, - "static/image/white-shapes/triangle-512.png": static_image_white_shapes_triangle_512_png, - "static/image/white-shapes/triangle-64.png": static_image_white_shapes_triangle_64_png, - "static/image/white-shapes/triangle-outline-128.png": static_image_white_shapes_triangle_outline_128_png, - "static/image/white-shapes/triangle-outline-16.png": static_image_white_shapes_triangle_outline_16_png, - "static/image/white-shapes/triangle-outline-24.png": static_image_white_shapes_triangle_outline_24_png, - "static/image/white-shapes/triangle-outline-256.png": static_image_white_shapes_triangle_outline_256_png, - "static/image/white-shapes/triangle-outline-32.png": static_image_white_shapes_triangle_outline_32_png, - "static/image/white-shapes/triangle-outline-48.png": static_image_white_shapes_triangle_outline_48_png, - "static/image/white-shapes/triangle-outline-512.png": static_image_white_shapes_triangle_outline_512_png, - "static/image/white-shapes/triangle-outline-64.png": static_image_white_shapes_triangle_outline_64_png, - "static/js/energyViewer.js": static_js_energyviewer_js, - "static/js/statsViewer.js": static_js_statsviewer_js, - "static/js/visualize.js": static_js_visualize_js, - "templates/energyViewer.html": templates_energyviewer_html, - "templates/statsViewer.html": templates_statsviewer_html, - "templates/visualize.html": templates_visualize_html, + "static/image/white-shapes/square-dashed-rounded-64.png": static_image_white_shapes_square_dashed_rounded_64_png, + "static/image/white-shapes/square-ios-app-128.png": static_image_white_shapes_square_ios_app_128_png, + "static/image/white-shapes/square-ios-app-16.png": static_image_white_shapes_square_ios_app_16_png, + "static/image/white-shapes/square-ios-app-24.png": static_image_white_shapes_square_ios_app_24_png, + "static/image/white-shapes/square-ios-app-256.png": static_image_white_shapes_square_ios_app_256_png, + "static/image/white-shapes/square-ios-app-32.png": static_image_white_shapes_square_ios_app_32_png, + "static/image/white-shapes/square-ios-app-48.png": static_image_white_shapes_square_ios_app_48_png, + "static/image/white-shapes/square-ios-app-512.png": static_image_white_shapes_square_ios_app_512_png, + "static/image/white-shapes/square-ios-app-64.png": static_image_white_shapes_square_ios_app_64_png, + "static/image/white-shapes/square-outline-128.png": static_image_white_shapes_square_outline_128_png, + "static/image/white-shapes/square-outline-16.png": static_image_white_shapes_square_outline_16_png, + "static/image/white-shapes/square-outline-24.png": static_image_white_shapes_square_outline_24_png, + "static/image/white-shapes/square-outline-256.png": static_image_white_shapes_square_outline_256_png, + "static/image/white-shapes/square-outline-32.png": static_image_white_shapes_square_outline_32_png, + "static/image/white-shapes/square-outline-48.png": static_image_white_shapes_square_outline_48_png, + "static/image/white-shapes/square-outline-512.png": static_image_white_shapes_square_outline_512_png, + "static/image/white-shapes/square-outline-64.png": static_image_white_shapes_square_outline_64_png, + "static/image/white-shapes/square-rounded-128.png": static_image_white_shapes_square_rounded_128_png, + "static/image/white-shapes/square-rounded-16.png": static_image_white_shapes_square_rounded_16_png, + "static/image/white-shapes/square-rounded-24.png": static_image_white_shapes_square_rounded_24_png, + "static/image/white-shapes/square-rounded-256.png": static_image_white_shapes_square_rounded_256_png, + "static/image/white-shapes/square-rounded-32.png": static_image_white_shapes_square_rounded_32_png, + "static/image/white-shapes/square-rounded-48.png": static_image_white_shapes_square_rounded_48_png, + "static/image/white-shapes/square-rounded-512.png": static_image_white_shapes_square_rounded_512_png, + "static/image/white-shapes/square-rounded-64.png": static_image_white_shapes_square_rounded_64_png, + "static/image/white-shapes/triangle-128.png": static_image_white_shapes_triangle_128_png, + "static/image/white-shapes/triangle-16.png": static_image_white_shapes_triangle_16_png, + "static/image/white-shapes/triangle-24.png": static_image_white_shapes_triangle_24_png, + "static/image/white-shapes/triangle-256.png": static_image_white_shapes_triangle_256_png, + "static/image/white-shapes/triangle-32.png": static_image_white_shapes_triangle_32_png, + "static/image/white-shapes/triangle-48.png": static_image_white_shapes_triangle_48_png, + "static/image/white-shapes/triangle-512.png": static_image_white_shapes_triangle_512_png, + "static/image/white-shapes/triangle-64.png": static_image_white_shapes_triangle_64_png, + "static/image/white-shapes/triangle-outline-128.png": static_image_white_shapes_triangle_outline_128_png, + "static/image/white-shapes/triangle-outline-16.png": static_image_white_shapes_triangle_outline_16_png, + "static/image/white-shapes/triangle-outline-24.png": static_image_white_shapes_triangle_outline_24_png, + "static/image/white-shapes/triangle-outline-256.png": static_image_white_shapes_triangle_outline_256_png, + "static/image/white-shapes/triangle-outline-32.png": static_image_white_shapes_triangle_outline_32_png, + "static/image/white-shapes/triangle-outline-48.png": static_image_white_shapes_triangle_outline_48_png, + "static/image/white-shapes/triangle-outline-512.png": static_image_white_shapes_triangle_outline_512_png, + "static/image/white-shapes/triangle-outline-64.png": static_image_white_shapes_triangle_outline_64_png, + "static/js/energyViewer.js": static_js_energyviewer_js, + "static/js/statsViewer.js": static_js_statsviewer_js, + "static/js/visualize.js": static_js_visualize_js, + "templates/energyViewer.html": templates_energyviewer_html, + "templates/statsViewer.html": templates_statsviewer_html, + "templates/visualize.html": templates_visualize_html, } // AssetDir returns the file names below a certain // directory embedded in the file by go-bindata. // For example if you run go-bindata on data/... and data contains the // following hierarchy: -// -// data/ -// foo.txt -// img/ -// a.png -// b.png -// +// data/ +// foo.txt +// img/ +// a.png +// b.png // then AssetDir("data") would return []string{"foo.txt", "img"} // AssetDir("data/img") would return []string{"a.png", "b.png"} // AssetDir("foo.txt") and AssetDir("notexist") would return an error @@ -1874,14 +1872,20 @@ var _bintree = &_bintree_t{nil, map[string]*_bintree_t{ }}, }}, "js": &_bintree_t{nil, map[string]*_bintree_t{ - "energyViewer.js": &_bintree_t{static_js_energyviewer_js, map[string]*_bintree_t{}}, - "statsViewer.js": &_bintree_t{static_js_statsviewer_js, map[string]*_bintree_t{}}, - "visualize.js": &_bintree_t{static_js_visualize_js, map[string]*_bintree_t{}}, + "energyViewer.js": &_bintree_t{static_js_energyviewer_js, map[string]*_bintree_t{ + }}, + "statsViewer.js": &_bintree_t{static_js_statsviewer_js, map[string]*_bintree_t{ + }}, + "visualize.js": &_bintree_t{static_js_visualize_js, map[string]*_bintree_t{ + }}, }}, }}, "templates": &_bintree_t{nil, map[string]*_bintree_t{ - "energyViewer.html": &_bintree_t{templates_energyviewer_html, map[string]*_bintree_t{}}, - "statsViewer.html": &_bintree_t{templates_statsviewer_html, map[string]*_bintree_t{}}, - "visualize.html": &_bintree_t{templates_visualize_html, map[string]*_bintree_t{}}, + "energyViewer.html": &_bintree_t{templates_energyviewer_html, map[string]*_bintree_t{ + }}, + "statsViewer.html": &_bintree_t{templates_statsviewer_html, map[string]*_bintree_t{ + }}, + "visualize.html": &_bintree_t{templates_visualize_html, map[string]*_bintree_t{ + }}, }}, }}