キャンセル
次の結果を表示 
次の代わりに検索 
もしかして: 
cancel
1226
閲覧回数
10
いいね!
0
コメント
mnagao
Cisco Employee
Cisco Employee

 

 

はじめに

Cisco DNA Center は Docker/Kubernetes 上で稼働する、各種 OSS を活用した Web アプリケーションです。
動作の概要を理解するためには API (REST API や GraphQL)、docker log, パケットキャプチャなどを組み合わせて調べることになりますが、ここでは比較的シンプルなアプリケーションである Command Runner を例に動作概要把握の流れをご紹介します。

IOS などと異なり、Cisco 独自の要素は多くありませんが、Automation については Prime Infrastructure や APIC-EM の流れを汲む実装となっており、ログなどの特徴は似ています。

 

Command Runner は Web ブラウザ上で一部の CLI をエミュレートするアプリケーションです。Device 360 等で Run Commands をクリックすることなどにより実行できます。

command-runner-1.png

 

API

ブラウザの開発者ツールで HTTP トレースを取得しながら Command Runner を実行すると以下のような API によりこの機能が実現されていることが分かります。

network-device-poller/cli/legit-reads API にアクセスし、実行可能なコマンドを取得します。ブラウザはロードされている JavaScript により入力された文字列が実行可能コマンドであるかどうかをチェックします。

command-runner-2.pngcommand-runner-3.png

なお、network-device-poller API は DNA Center が使用している API Gateway である Kong により、command-runner-service Service (Kubernetes サービス) 経由で command-runnner-service Pod にルーティングされます。

[Thu Jul 23 20:05:59 UTC] maglev@10.70.70.231 (maglev-master-1) ~
$ magctl api routes  <-- Kong の API 定義確認
    (snip)
    {
      "http_if_terminated": false, 
      "retries": 0, 
      "name": "fusion_command-runner-service_network-device-poller", 
      "https_only": false, 
      "upstream_url": "http://command-runner-service.fusion.svc.cluster.local:17015/network-device-poller", 
      "strip_uri": true, 
      "created_at": 1594052309747, 
      "uris": [
        "/api/v1/network-device-poller"
      ], 
    (snip)

    
[Thu Jul 23 20:08:44 UTC] maglev@10.70.70.231 (maglev-master-1) ~
$ kubectl get pods -n fusion -o wide | egrep "command-runner|IP"
NAME                                                     READY     STATUS    RESTARTS   AGE       IP            NODE        NOMINATED NODE
command-runner-service-87649dc96-ssgg6                   1/1       Running   0          17d       10.61.3.190   192.0.2.2   

[Thu Jul 23 20:09:13 UTC] maglev@10.70.70.231 (maglev-master-1) ~
$ kubectl get services -n fusion  | egrep "command-runner|TYPE"
NAME                                    TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                               AGE
command-runner-service                  ClusterIP   10.62.1.215           17015/TCP                             1y

[Thu Jul 23 20:09:35 UTC] maglev@10.70.70.231 (maglev-master-1) ~
$ sudo iptables-save | grep command-runner
[sudo] password for maglev: 
-A KUBE-SEP-5YGOMRMMC42GKZEO -s 10.61.3.190/32 -m comment --comment "fusion/command-runner-service:default" -j KUBE-MARK-MASQ
-A KUBE-SEP-5YGOMRMMC42GKZEO -p tcp -m comment --comment "fusion/command-runner-service:default" -m tcp -j DNAT --to-destination 10.61.3.190:17015
-A KUBE-SERVICES ! -s 10.61.0.0/21 -d 10.62.1.215/32 -p tcp -m comment --comment "fusion/command-runner-service:default cluster IP" -m tcp --dport 17015 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.62.1.215/32 -p tcp -m comment --comment "fusion/command-runner-service:default cluster IP" -m tcp --dport 17015 -j KUBE-SVC-XM3YN2Z4G7FFSE5R
-A KUBE-SVC-XM3YN2Z4G7FFSE5R -m comment --comment "fusion/command-runner-service:default" -j KUBE-SEP-5YGOMRMMC42GKZEO

 

ユーザにより入力された CLI コマンドは command-runner-service Pod の network-device-poller/read-request API へ HTTP POST されます。
ブラウザから POST される JSON には CLI コマンド (例では sh ver) だけでなく、対象とするデバイスの UUID が指定されます。POST に対するレスポンスには、DNA Center 内での処理を識別するための task ID と task ID へアクセスするための URL が含まれます。

command-runner-4.png

command-runner-5.png

 

task/{taskId} API へアクセスすると、タスクの進捗状況が分かります。最初は progress:"CLI Runner request creation" ですが、何度か API へのアクセスを繰り返す内に endTime:{unixtime} が追加され、progress には fileId が提供されることでタスクの完了が通知されます。(/api/v1/task/ API は task-service Pod へルーティングされます)

command-runner-6.pngcommand-runner-7.pngcommand-runner-8.png


タスクが完了し、fileId が提供されるとブラウザ上で稼働する JavaScript は file API へアクセスし、CLI コマンドの出力結果を JSON として受け取ります。Device 360 からの Command Runner 実行では 1 台のデバイスに対して CLI コマンドを実行するため実行結果を一時ファイルとして保存する必要性は感じませんが、Tools > Command Runner からの CLI コマンド実行では複数デバイスに対して複数コマンドを一括実行できるため、実行結果をファイルとして扱う実装が適当です。
(file API は file-service Pod へルーティングされます)

command-runner-9.pngcommand-runner-10.png


以上が Web ブラウザでの HTTP (API) トレースから分かる動作概要ですが、これだけでは内部動作は分かりません。

 

docker log

magctl service logs -rf {Pod名} (docker logs -f 相当) で Pod のリアルタイムログを取得できます。このログからは REST API 通信の他に、PostgreSQL や AMQP(RabbitMQ) が関与していることが分かります。(注: magctl service logs について、Pod に複数コンテナが含まれる場合は -c オプションでコンテナの指定が必要です) 

こちらは System Settings > Settings > Debugging Logs にて Logging Levelを Debug にした際の抜粋で取得時刻は HTTP トレース、パケットキャプチャとは異なります。これらと同時刻 (Logging Level = INFO) のものは添付をご参照ください)

[Sat Jul 25 23:51:22 UTC] maglev@10.70.70.231 (maglev-master-1) ~
$ magctl service logs -rf command-runner

// 実行可能コマンドの取得
2020-07-26 00:02:34,509 |   INFO | qtp1028780142-24659       |  | c.c.a.c.r.s.c.CommandRunnerController | Valid CLI keywords are: [call-home, cd, cping, crypto, dir, eping, grep, help, mediatrace, monitor, more, mping, mstat, ping, pwd, sdlc, show, sh, standby, start-chat, systat, tarp, test, traceroute, ucse, verify, where, which-route] | 

// デバイスのインベントリ情報を PostgreSQL から取得
2020-07-26 00:02:37,179 |   INFO | qtp1028780142-24659       |  | c.c.a.c.r.s.util.InventoryUtil | deviceuuids in inside[4114cd20-56b8-4f42-852d-31875a94b5e6] | 
2020-07-26 00:02:37,183 |   INFO | qtp1028780142-24659       |  | c.c.a.c.r.s.util.InventoryUtil | nwdevice :: getWapdevicesList method {}NetworkDevice[apManagerInterfaceIp=,associatedWlcIp=,bootDateTime=2020-07-20 01:41:00,collectionInterval=Global Default,collectionStatus=Managed,description=Cisco IOS Software [Gibraltar], Catalyst L3 Switch Software (CAT9K_IOSXE), Version 16.12.3s, RELEASE SOFTWARE (fc1) Technical Support: http://www.cisco.com/techsupport Copyright (c) 1986-2020 by Cisco Systems, Inc. Compiled Tue 19-May-20 11:48 by mcpre,deviceSupportLevel=Supported,family=Switches and Hubs,hostname=tky-dna2-edge2.cisco.com,interfaceCount=0,inventoryStatusDetail=,lastUpdateTime=2020-07-26 00:00:00.581,lastUpdated=2020-07-26 00:00:00,lineCardCount=0,lineCardId=,macAddress=70:18:a7:1e:64:80,managementIpAddress=192.168.12.11,memorySize=NA,paddedMgmtIpAddress=192.168. 12. 11,platformId=C9300-48P, C9300-48P,reachabilityFailureReason=,reachabilityStatus=Reachable,role=ACCESS,roleSource=AUTO,serialNumber=FCW2244AHRR, FCW2137G0MN,series=Cisco Catalyst 9300 Series Switches,snmpContact=,snmpLocation=,softwareType=IOS-XE,softwareVersion=16.12.3s,tagCount=0,type=Cisco Catalyst 9300 Switch,upTime=5 days, 22:19:06.56,uptimeSeconds=512497,instanceUuid=4114cd20-56b8-4f42-852d-31875a94b5e6,instanceId=814565764,authEntityId=814565764,authEntityClass=-927529445,instanceTenantId=5cb85950179074004c58a503,_orderedListOEIndex=,_creationOrderIndex=,_isBeingChanged=,deployPending=,instanceVersion=0] | 
2020-07-26 00:02:37,306 |   INFO | qtp1028780142-24659       |  | c.c.a.c.r.s.util.InventoryUtil | meiList :: ValidateDevices method [ManagedElementInterface[assignedNetworkRoles=[UNKNOWN],autoIpSwapEnabled=false,collectionInterval=-1,communicationState=REACHABLE,createTime=2020-07-20 01:44:26.32,discoverySource=UNKNOWN,entityId=814565764,featureSupportLevel=FULL_SUPPORT,inventoryCollectionTime=2020-07-26 00:00:00.581,inventoryStatusDetail=,lastBootTime=2020-07-20 01:41:00.582,lastIcmpPingTime=0,lastInventoryAttemptEndTime=2020-07-26 00:00:00.581,lastInventoryAttemptStartTime=2020-07-25 23:59:44.621,lifecycleState=MANAGED_AND_SYNCHRONIZED,managementAddress=192.168.12.11,paddedMgmtAddress=192.168. 12. 11,description=,name=,instanceUuid=4114cd20-56b8-4f42-852d-31875a94b5e6,instanceId=814565764,authEntityId=814565764,authEntityClass=-927529445,instanceTenantId=5cb85950179074004c58a503,_orderedListOEIndex=,_creationOrderIndex=,_isBeingChanged=,deployPending=,instanceVersion=0]] | 

// CLI コマンドと実行対象デバイスの情報を networkpoller へ送信
2020-07-26 00:02:37,308 |   INFO | qtp1028780142-24659       |  | c.c.a.c.r.s.util.CommandRunnerUtil | items : [sh ver], delimiter : ; | 
2020-07-26 00:02:37,309 |  DEBUG | qtp1028780142-24659       |  | c.c.enc.audit.impl.AuditClientImpl | Sending Audit message with TaskId to queue CreateAuditTaskMessage {context=null, replyToChain=null, version=1595721757309, payload=Request [auditInstanceUUID=c56d77ec-17f6-4ad6-bf4a-0119f37bec6d, taskId=5349c1a5-0daf-4240-beb2-7372d84a38cc, auditDescription=CLI Runner request creation, auditRequestor=admin, siteName=null, deviceIp=null, deviceName=null, tag=Command Runner, auditMap={COMMANDS=sh ver, DEVICE_UUIDS=4114cd20-56b8-4f42-852d-31875a94b5e6}, createdDateTime=Sun Jul 26 00:02:37 UTC 2020]} | 
2020-07-26 00:02:37,310 |  DEBUG | qtp1028780142-24659       |  | com.cisco.xmp.persistence.impl.DMM | @@@Calling session save for the instance:com.cisco.apicem.networkpoller.model.commandrunner.CommandRunnerRequest | 
2020-07-26 00:02:37,313 |  DEBUG | qtp1028780142-24659       |  | c.c.enc.audit.impl.AuditClientImpl | Sending Audit message with TaskId to queue CreateAuditTaskMessage {context=null, replyToChain=null, version=1595721757313, payload=Request [auditInstanceUUID=c48f9804-a737-45f1-b355-a55d095fd963, taskId=05819539-21af-4e21-b03f-e0db40f3cc18, auditDescription=Execution of commands on device : 4114cd20-56b8-4f42-852d-31875a94b5e6STARTED, auditRequestor=admin, siteName=null, deviceIp=null, deviceName=null, tag=Command Runner, auditMap={COMMANDS=sh ver, DEVICE_UUIDS=4114cd20-56b8-4f42-852d-31875a94b5e6}, createdDateTime=Sun Jul 26 00:02:37 UTC 2020]} | 

 // networkpoller より CLI コマンド実行結果を AMQP (RabbitMQ) で取得
2020-07-26 00:02:37,329 |  DEBUG | qtp1028780142-24659       |  | c.c.a.c.r.s.m.CommandRunnerMessageFactory | Constructing commandRunner message for device : 192.168.12.11 & commands : [sh ver] with timeout : 0 | 
2020-07-26 00:02:37,339 |   INFO | qtp1028780142-24659       |  | c.c.a.c.r.s.m.CommandRunnerMessageFactory | Message is : XdeRunnerMessage {context={public={serviceType=Command Runner Service}}, replyToChain=[null://clirunner.response.exchange/clirunner.response.routing], version=0, payload=com.cisco.enc.networkpoller.api.request.xderunner.XdeRunnerMessage$Request@6e77baf2} | 
2020-07-26 00:02:37,339 |  DEBUG | qtp1028780142-24659       |  | c.c.a.c.r.s.c.CommandRunnerController | Message successfully submitted for device : 4114cd20-56b8-4f42-852d-31875a94b5e6 | 
2020-07-26 00:02:37,523 |  DEBUG | SimpleAsyncTaskExecutor-4 |  | c.c.g.a.i.GrapevineMessageListener | Received message=com.cisco.grapevine.amqp.message.result.SuccessResultMessage, retries=0, maxRetries=5 | 
2020-07-26 00:02:37,524 |  DEBUG | SimpleAsyncTaskExecutor-4 |  | c.c.a.c.r.s.r.XdeRunnerMessageResultHandler | command response {sh ver=sh ver
Cisco IOS XE Software, Version 16.12.03s
Cisco IOS Software [Gibraltar], Catalyst L3 Switch Software (CAT9K_IOSXE), Version 16.12.3s, RELEASE SOFTWARE (fc1)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2020 by Cisco Systems, Inc.
Compiled Tue 19-May-20 11:48 by mcpre
...
...
Configuration register is 0x102

// CLI 実行結果を file-service へアップロード
2020-07-26 00:02:37,524 |  DEBUG | SimpleAsyncTaskExecutor-4 |  | c.c.a.c.r.s.r.XdeRunnerMessageResultHandler | command response {} | 
2020-07-26 00:02:37,524 |  DEBUG | SimpleAsyncTaskExecutor-4 |  | c.c.a.c.r.s.r.XdeRunnerMessageResultHandler | Command output to persist {"SUCCESS":{"sh ver":"sh ver\nCisco IOS XE Software, Version 16.12.03s\nCisco IOS Software [Gibraltar], ... "},"FAILURE":{},"BLACKLISTED":{}} | 

2020-07-26 00:02:37,537 |  DEBUG | SimpleAsyncTaskExecutor-4 |  | c.c.a.c.r.s.c.f.FileServiceInteractorImpl | get internal upload url Return object: SuccessResultMessage {context={public={RBACSecurityContext=eyJ0eXA ... }}, replyToChain=null, version=0, payload=/api/v1/file/internalupload/d2796681-a970-4286-9877-6e8fa08c3d73} | 
2020-07-26 00:02:37,537 |  DEBUG | SimpleAsyncTaskExecutor-4 |  | c.c.a.c.r.s.c.f.FileServiceInteractorImpl | Unique Internal Upload id is :: d2796681-a970-4286-9877-6e8fa08c3d73 | 
2020-07-26 00:02:37,556 |  DEBUG | SimpleAsyncTaskExecutor-4 |  | c.c.e.c.c.f.ServiceInstanceManagerImpl | Endpoint URL manufactured from service instance IP 10.61.3.168 and port 16020 is http://10.61.3.168:16020 | 
2020-07-26 00:02:37,556 |  DEBUG | SimpleAsyncTaskExecutor-4 |  | c.c.e.c.c.f.FileServiceRestClientEngine | file-service port =16020 | 
2020-07-26 00:02:37,801 |   INFO | SimpleAsyncTaskExecutor-4 |  | c.c.a.c.r.s.c.f.FileServiceInteractorImpl | File created..fileUuid d2796681-a970-4286-9877-6e8fa08c3d73 | 
2020-07-26 00:02:37,801 |  DEBUG | SimpleAsyncTaskExecutor-4 |  | c.c.a.c.r.s.r.XdeRunnerMessageResultHandler | Need to udapte the task 5349c1a5-0daf-4240-beb2-7372d84a38cc | 

2020-07-26 00:02:37,802 |  DEBUG | SimpleAsyncTaskExecutor-4 |  | c.c.g.a.i.MaglevAppContainerMessagePropertiesConverter | All done. The message is now ready to be sent to a maglev based app container. | 
2020-07-26 00:02:37,806 |  DEBUG | SimpleAsyncTaskExecutor-4 |  | c.c.g.a.i.GrapevineMessageListener | Handler returned result: SuccessResultMessage {context={public={serviceType=Command Runner Service, RBACSecurityContext=eyJ0eXA ... , context.taskid=05819539-21af-4e21-b03f-e0db40f3cc18, COMMANDS=sh ver, isCommandRunner=true}, clirunner.workflow={deviceUuid=4114cd20-56b8-4f42-852d-31875a94b5e6, invalidDevices=, requestorUsername=admin, parentTaskId=5349c1a5-0daf-4240-beb2-7372d84a38cc, requestUuid=a61cbf44-cb80-4773-aef8-2c81e431b1e2, Processing Devices=, Blacklisted Commands=}}, replyToChain=[], version=0, payload={"SUCCESS":{"actualValue":{"sh ver":"sh ver\nCisco IOS XE Software, Version 16.12.03s\nCisco IOS Software [Gibraltar], Catalyst L3 Switch Software (CAT9K_IOSXE), Version 16.12.3s, RELEASE SOFTWARE (fc1)\nTechnical Support: http://www.cisco.com/techsupport\nCopyright (c) 1986-2020 by Cisco Systems, Inc.\nCompiled Tue 19-May-20 11:48 by mcpre\n\n\nCisco IOS-XE software, Copyright (c) 2005-2020 by cisco Systems, Inc. ...  \n\nConfiguration register is 0x102\n\ntky-dna2-edge2#"},"valueType":{}},"FAILURE":{"actualValue":{},"valueType":{}},"BLACKLISTED":{"actualValue":{},"valueType":{}}}}) | 

  

  

パケットキャプチャ

DNAC: tcpdump による特定 Pod のパケットキャプチャ のような手順で command-runner-service Pod についてパケットキャプチャを取得し、キャプチャファイルを HTTP トレースや docker log と組み合わせると、もう少し具体的な挙動を理解できます。関連する Pod は以下です。

[Fri Jul 24 12:50:30 UTC] maglev@10.70.70.231 (maglev-master-1) ~
$ kubectl get pods --all-namespaces -o wide | egrep "IP|kong|command-runner|postgres|network-poller|rabbitmq|maglevserver|task-service" | grep -v app-hosting
NAMESPACE                  NAME                                                     READY     STATUS      RESTARTS   AGE       IP            NODE        NOMINATED NODE
fusion                     command-runner-service-87649dc96-ssgg6                   1/1       Running     0          19d       10.61.3.190   192.0.2.2   
fusion                     network-poller-service-5b648cd98b-tkvqn                  1/1       Running     0          19d       10.61.3.144   192.0.2.2   
fusion                     postgres-0                                               3/3       Running     0          19d       10.61.3.26    192.0.2.2   
fusion                     task-service-55b6d7d8fb-5t6vd                            1/1       Running     0          19d       10.61.3.19    192.0.2.2   
maglev-system              kong-56986f66d6-9xpvc                                    2/2       Running     0          19d       10.61.3.18    192.0.2.2   
maglev-system              maglevserver-58bd6c7b67-v6jvg                            1/1       Running     0          19d       10.61.3.17    192.0.2.2   
maglev-system              rabbitmq-0                                               2/2       Running     0          19d       10.61.3.46    192.0.2.2   

 

ブラウザからの network-device-poller/cli/legit-reads API リクエストが kong Pod (10.61.3.18) 経由で command-runner-service (10.61.3.190) に届くと、command-runner-service は AMQP (RabbitMQ) 経由で network-poller-service に実行可能コマンドを問い合わせます。 network-poller-service からの応答がブランクなのはデフォルトだからです。これを受けて command-runner-service は Kong 経由でブラウザにレスポンスを返します。

command-runner-18.png

(Kong が付加した HTTP X-* ヘッダよりレスポンスの宛先 API クライアント (Web ブラウザ) の IP が 10.70.232.47 でプロトコルは HTTPS、ブラウザが Mac 版 Chrome v84 といったことも分かります。)

command-runner-26.png

command-runner-28.png

command-runner-31.png


ユーザが CLI コマンドを入力すると、Kong 経由で command-runner-service の network-device-poller/cli/read-request API へ CLI コマンド (sh ver) が POST されます。

command-runner-40.png

command-runner-service は PostgreSQL へクエリを実行し、当該デバイスの情報を取得したり、

command-runner-49.png

command-runner-50.png

 

タスクの進捗管理のために task-service Pod との連携を行います。

command-runner-77.pngcommand-runner-95.png

 

HTTP POST で受け取った CLI コマンドは AMQP で network-poller-service へ渡され、network-poller-service がデバイスに SSH を行います。 

command-runner-160.png

network-poller-service の挙動については、ここでは説明しませんが、デバイスへの SSH を行うのが network-poller-service であることは conntrack コマンドなどでも確認できます。

[Sat Jul 25 22:39:21 UTC] maglev@10.70.70.231 (maglev-master-1) ~
$ sudo conntrack -E -d 192.168.12.11
[sudo] password for maglev: 
    [NEW] tcp      6 120 SYN_SENT src=10.61.3.144 dst=192.168.12.11 sport=37854 dport=22 [UNREPLIED] src=192.168.12.11 dst=192.168.1.20 sport=22 dport=37854
 [UPDATE] tcp      6 60 SYN_RECV src=10.61.3.144 dst=192.168.12.11 sport=37854 dport=22 src=192.168.12.11 dst=192.168.1.20 sport=22 dport=37854
 [UPDATE] tcp      6 86400 ESTABLISHED src=10.61.3.144 dst=192.168.12.11 sport=37854 dport=22 src=192.168.12.11 dst=192.168.1.20 sport=22 dport=37854 [ASSURED]
^Cconntrack v1.4.3 (conntrack-tools): 3 flow events have been shown.

[Sat Jul 25 22:39:52 UTC] maglev@10.70.70.231 (maglev-master-1) ~
$ sudo conntrack -L -n | grep 10.61.3.144 | grep 22
conntrack v1.4.3 (conntrack-tools): 60 flow entries have been shown.
tcp      6 86379 ESTABLISHED src=10.61.3.144 dst=192.168.12.11 sport=37854 dport=22 src=192.168.12.11 dst=192.168.1.20 sport=22 dport=37854 [ASSURED] mark=0 use=1

[Sat Jul 25 22:42:07 UTC] maglev@10.70.70.231 (maglev-master-1) ~
$ kubectl get pods --all-namespaces -o wide | egrep "IP|10\.61\.3\.144"
NAMESPACE                  NAME                                                     READY     STATUS      RESTARTS   AGE       IP            NODE        NOMINATED NODE
fusion                     network-poller-service-5b648cd98b-tkvqn                  1/1       Running     0          19d       10.61.3.144   192.0.2.2   

 

HTTP POST に対してはレスポンスで taskId が通知されますので、ブラウザは task-service に API アクセスすることで task の進捗などを確認できます。

command-runner-162.png

 

network-polller-service から AMQP で CLI コマンドの出力結果が command-runner-service に渡され、task-service に進捗がアップデートされます。

command-runner-167.png

command-runner-175.png

 

command-runner-service は AMQP で CLI コマンド出力結果のアップロード先を file-service に問い合わせて fileId を取得します。

command-runner-195.png

command-runner-196.png

 

command-runner-service はファイルをアップロードする前に maglevserver から file-service の各種プロパティを取得します。
maglevserver Pod は maglev-system namespace 内の各種 OSS を含むミドルウェア群を取りまとめる Pod で Kubernetes における kube-apiserver のような位置付けの Pod です。

command-runner-206-208.png

 

command-runner-service はファイルを file-service へ POST し、task-service に endTime と fileId を通知します。当該 taskId へ API アクセスしているブラウザは fileId を知ることで CLI コマンドの結果へアクセス可能になります。

command-runner-219-221.png

command-runner-237.png

 

Getting Started

検索バーにキーワード、フレーズ、または質問を入力し、お探しのものを見つけましょう

シスコ コミュニティをいち早く使いこなしていただけるよう役立つリンクをまとめました。みなさんのジャーニーがより良いものとなるようお手伝いします