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
58 changes: 52 additions & 6 deletions .github/workflows/CI.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ concurrency:
group: skywalking-cli-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

# OAP image tag used by the E2E suites. Must be an admin-capable build: the admin-server
# REST host (port 17128), queryAlarms and the menu retirement landed in OAP 11.0.0; the
# OAL live-debugging case additionally needs the demo traffic to drive the captured pipeline.
env:
OAP_TAG: 768d0693aac34ed49ce4d1c89e4a56df353e4140

jobs:
check-license:
name: License header
Expand Down Expand Up @@ -85,10 +91,6 @@ jobs:
name: Command Tests
runs-on: ubuntu-latest
if: github.repository == 'apache/skywalking-cli'
strategy:
matrix:
oap:
- 42c613bea94999a6cc8e805ed4c8c7659f3a735c
steps:
- uses: actions/checkout@v4
- name: Set up Go
Expand All @@ -101,12 +103,50 @@ jobs:

- name: Test commands
uses: apache/skywalking-infra-e2e@cf589b4a0b9f8e6f436f78e9cfd94a1ee5494180
env:
OAP_TAG: ${{ matrix.oap }}
with:
e2e-file: test/cases/basic/test.yaml


admin-command-tests:
name: Admin Command Tests
runs-on: ubuntu-latest
if: github.repository == 'apache/skywalking-cli'
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.26"

- name: Install swctl
run: make install DESTDIR=/usr/local/bin

- name: Test admin commands
uses: apache/skywalking-infra-e2e@cf589b4a0b9f8e6f436f78e9cfd94a1ee5494180
with:
e2e-file: test/cases/admin/test.yaml


live-debugging-tests:
name: Live Debugging Tests
runs-on: ubuntu-latest
if: github.repository == 'apache/skywalking-cli'
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.26"

- name: Install swctl
run: make install DESTDIR=/usr/local/bin

- name: Test OAL live debugging
uses: apache/skywalking-infra-e2e@cf589b4a0b9f8e6f436f78e9cfd94a1ee5494180
with:
e2e-file: test/cases/live-debugging/test.yaml


unit-tests:
name: Unit Tests
runs-on: ubuntu-latest
Expand All @@ -130,6 +170,8 @@ jobs:
- check-license
- build
- command-tests
- admin-command-tests
- live-debugging-tests
- unit-tests
runs-on: ubuntu-latest
timeout-minutes: 10
Expand All @@ -140,8 +182,12 @@ jobs:
[[ ${checkLicense} == 'success' ]] || exit 1;
build=${{ needs.build.result }};
commandTests=${{ needs.command-tests.result }};
adminCommandTests=${{ needs.admin-command-tests.result }};
liveDebuggingTests=${{ needs.live-debugging-tests.result }};
unitTests=${{ needs.unit-tests.result }};
[[ ${build} == 'success' ]] || [[ ${build} == 'skipped' ]] || exit 3;
[[ ${commandTests} == 'success' ]] || [[ ${commandTests} == 'skipped' ]] || exit 4;
[[ ${adminCommandTests} == 'success' ]] || [[ ${adminCommandTests} == 'skipped' ]] || exit 6;
[[ ${liveDebuggingTests} == 'success' ]] || [[ ${liveDebuggingTests} == 'skipped' ]] || exit 7;
[[ ${unitTests} == 'success' ]] || [[ ${unitTests} == 'skipped' ]] || exit 5;
exit 0;
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@ Release Notes.
* Add the duration field in the `trace list` command by @mrproliu in https://github.com/apache/skywalking-cli/pull/225
* Remove the oldest `queryTraceFromColdStage` query call in the `trace list` command by @mrproliu in https://github.com/apache/skywalking-cli/pull/225
* Add the sub-command `profiling pprof` for pprof query API by @JophieQu in https://github.com/apache/skywalking-cli/pull/226
* Add the `admin` command group for the OAP admin-server REST host (default port `17128`), with a new global `--admin-url` flag (derived from `--base-url` when unset). Covers every admin feature module: `admin preflight`; `admin cluster nodes`, `admin config dump|ttl`, `admin alarm rules|rule` (status); `admin inspect metrics|entities` (inspect); `admin ui-template list|get|create|update|disable` (ui-management); `admin runtime-rule list|bundled|get|add|inactivate|delete|dump` (runtime-rule); and `admin dsl-debug status|sessions|session start|get|stop` plus `admin oal files|file|rules|rule` (dsl-debugging).

### Bug Fixes

* Fix wrong process id format by @mrproliu in https://github.com/apache/skywalking-cli/pull/215
* Migrate `alarm list` from the deprecated `getAlarm` GraphQL query to `queryAlarms`, adding `--layer` and `--rules` filters (OAP 11.0.0).
* `menu get` now reports a clear message when the OAP backend no longer serves the UI menu (retired in OAP 11.0.0) instead of a raw GraphQL error.

0.14.0
------------------
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ The compatibility table here only lists fully compatible OAP versions, which mea
| \> = 0.12.0 | \> = 9.5.0 |
| \> = 0.13.0 | \> = 9.6.0 |
| \> = 0.14.0 | \> = 10.2.0 |
| \> = 0.15.0 | \> = 11.0.0 |

# Contributing

Expand Down
4 changes: 2 additions & 2 deletions assets/graphqls/alarm/alarms.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
# specific language governing permissions and limitations
# under the License.

query ($duration: Duration!, $scope: Scope, $keyword: String, $paging: Pagination!, $tags: [AlarmTag]) {
result: getAlarm(duration: $duration, scope: $scope, keyword: $keyword, paging: $paging, tags: $tags) {
query ($condition: AlarmQueryCondition!) {
result: queryAlarms(condition: $condition) {
msgs {
startTime
scope
Expand Down
11 changes: 11 additions & 0 deletions cmd/swctl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"os"
"runtime"

"github.com/apache/skywalking-cli/internal/commands/admin"
"github.com/apache/skywalking-cli/internal/commands/alarm"
"github.com/apache/skywalking-cli/internal/commands/browser"
"github.com/apache/skywalking-cli/internal/commands/completion"
Expand Down Expand Up @@ -115,6 +116,7 @@ services, service instances, etc.`
records.Command,
menu.Command,
hierarchy.Command,
admin.Command,
}

app.Before = interceptor.BeforeChain(
Expand Down Expand Up @@ -150,6 +152,15 @@ func flags() []cli.Flag {
Usage: "base `url` of the OAP backend graphql service",
Value: "http://127.0.0.1:12800/graphql",
}),
altsrc.NewStringFlag(&cli.StringFlag{
Name: "admin-url",
Required: false,
EnvVars: []string{"SW_ADMIN_URL"},
Usage: "base `url` of the OAP admin-server REST service (default port 17128), " +
"used by `swctl admin ...` sub-commands. If empty, it is derived from `--base-url` " +
"by reusing its host with port 17128.",
Value: "",
}),
altsrc.NewStringFlag(&cli.StringFlag{
Name: "grpc-addr",
Usage: "backend gRPC service address `<host:port>`",
Expand Down
3 changes: 3 additions & 0 deletions examples/.skywalking.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
# under the License.

base-url: http://demo.skywalking.apache.org/graphql
# admin-url is the OAP admin-server REST host used by `swctl admin ...` sub-commands.
# When omitted, it is derived from base-url's host with port 17128.
admin-url: http://demo.skywalking.apache.org:17128
grpc-addr: 127.0.0.1:11800
username: basic-auth-username
password: basic-auth-password
59 changes: 59 additions & 0 deletions internal/commands/admin/admin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Licensed to Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Apache Software Foundation (ASF) licenses this file to you 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 admin

import (
"github.com/urfave/cli/v2"

"github.com/apache/skywalking-cli/internal/commands/admin/alarm"
"github.com/apache/skywalking-cli/internal/commands/admin/cluster"
"github.com/apache/skywalking-cli/internal/commands/admin/config"
"github.com/apache/skywalking-cli/internal/commands/admin/dsldebug"
"github.com/apache/skywalking-cli/internal/commands/admin/inspect"
"github.com/apache/skywalking-cli/internal/commands/admin/oal"
"github.com/apache/skywalking-cli/internal/commands/admin/runtimerule"
"github.com/apache/skywalking-cli/internal/commands/admin/uitemplate"
)

// Command is the parent of every sub-command that talks to the OAP admin-server
// REST host (default port 17128), as opposed to the public GraphQL surface on
// `--base-url` (default port 12800). The admin host bundles the status, inspect,
// ui-management, dsl-debugging and runtime-rule feature modules. Its address comes
// from `--admin-url` (or is derived from `--base-url` with port 17128).
var Command = &cli.Command{
Name: "admin",
Usage: "Admin (REST) sub-commands that talk to the OAP admin-server (default port 17128)",
UsageText: `Admin sub-commands call the OAP admin-server REST host, a separate surface from the
public GraphQL endpoint used by the other commands.

The admin host address defaults to the "--base-url" host with port 17128; override it
with the global "--admin-url" flag (or the SW_ADMIN_URL env var / "admin-url" config key).
The admin host has no built-in authentication and is expected to sit behind a gateway;
"--username"/"--password"/"--authorization" and "--insecure" apply to it the same way.`,
Subcommands: []*cli.Command{
preflightCommand,
cluster.Command,
config.Command,
alarm.Command,
inspect.Command,
uitemplate.Command,
runtimerule.Command,
dsldebug.Command,
oal.Command,
},
}
98 changes: 98 additions & 0 deletions internal/commands/admin/alarm/alarm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Licensed to Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Apache Software Foundation (ASF) licenses this file to you 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 alarm exposes the admin-server alarm runtime status (loaded rule
// definitions and per-entity evaluation/window state). This is distinct from the
// top-level `swctl alarm` command, which reads fired alarm records via GraphQL.
package alarm

import (
"fmt"

"github.com/urfave/cli/v2"

"github.com/apache/skywalking-cli/pkg/admin/preflight"
"github.com/apache/skywalking-cli/pkg/admin/status"
"github.com/apache/skywalking-cli/pkg/display"
"github.com/apache/skywalking-cli/pkg/display/displayable"
)

var Command = &cli.Command{
Name: "alarm",
Usage: "Inspect alarm runtime status from the admin-server `status` module",
UsageText: `Inspect the alarm-running kernel: loaded rule definitions and per-entity
evaluation/window state. This differs from "swctl alarm list", which returns fired
alarm records from the GraphQL surface.`,
Subcommands: []*cli.Command{
rulesCommand,
ruleCommand,
},
}

var rulesCommand = &cli.Command{
Name: "rules",
Usage: "List the loaded alarm rules per OAP node (GET /status/alarm/rules)",
UsageText: `List the loaded alarm rules, fanned out across every OAP node.

Examples:
1. List alarm rules:
$ swctl admin alarm rules`,
Action: func(ctx *cli.Context) error {
rules, err := status.AlarmRules(ctx.Context)
if err != nil {
return preflight.Explain(ctx.Context, err, preflight.ModuleStatus, "SW_STATUS")
}
return display.Display(ctx.Context, &displayable.Displayable{Data: rules})
},
}

var ruleCommand = &cli.Command{
Name: "rule",
Usage: "Show one alarm rule's definition and running state (GET /status/alarm/{ruleId}[/{entityName}])",
ArgsUsage: "<ruleId> [<entityName>]",
UsageText: `Show the definition and running state of a single alarm rule. When an
entity name is given, the per-entity evaluation/window state is returned instead.

Examples:
1. Show a rule's running state:
$ swctl admin alarm rule service_resp_time_rule

2. Show the per-entity state of a rule:
$ swctl admin alarm rule service_resp_time_rule mock_b_service`,
Action: func(ctx *cli.Context) error {
args := ctx.Args()
ruleID := args.Get(0)
if ruleID == "" {
return fmt.Errorf("a <ruleId> argument is required")
}
entityName := args.Get(1)

var (
result *status.ClusterAlarmStatus
err error
)
if entityName == "" {
result, err = status.AlarmRule(ctx.Context, ruleID)
} else {
result, err = status.AlarmRuleEntity(ctx.Context, ruleID, entityName)
}
if err != nil {
return preflight.Explain(ctx.Context, err, preflight.ModuleStatus, "SW_STATUS")
}
return display.Display(ctx.Context, &displayable.Displayable{Data: result})
},
}
52 changes: 52 additions & 0 deletions internal/commands/admin/cluster/cluster.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Licensed to Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Apache Software Foundation (ASF) licenses this file to you 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 cluster

import (
"github.com/urfave/cli/v2"

"github.com/apache/skywalking-cli/pkg/admin/preflight"
"github.com/apache/skywalking-cli/pkg/admin/status"
"github.com/apache/skywalking-cli/pkg/display"
"github.com/apache/skywalking-cli/pkg/display/displayable"
)

var Command = &cli.Command{
Name: "cluster",
Usage: "Inspect the OAP cluster from the admin-server `status` module",
Subcommands: []*cli.Command{
nodesCommand,
},
}

var nodesCommand = &cli.Command{
Name: "nodes",
Usage: "List the OAP cluster peer nodes (GET /status/cluster/nodes)",
UsageText: `List the OAP cluster peer nodes as seen by the cluster coordinator.

Examples:
1. List cluster nodes:
$ swctl admin cluster nodes`,
Action: func(ctx *cli.Context) error {
nodes, err := status.ClusterNodesQuery(ctx.Context)
if err != nil {
return preflight.Explain(ctx.Context, err, preflight.ModuleStatus, "SW_STATUS")
}
return display.Display(ctx.Context, &displayable.Displayable{Data: nodes})
},
}
Loading
Loading