{"id":44608351,"url":"https://github.com/shigechika/junos-ops","last_synced_at":"2026-05-08T07:04:55.313Z","repository":{"id":45350518,"uuid":"435056422","full_name":"shigechika/junos-ops","owner":"shigechika","description":"Python CLI to automate Juniper/JUNOS operations over NETCONF: model-aware upgrade, rollback, reboot, config push, and RSI/SCF collection","archived":false,"fork":false,"pushed_at":"2026-05-08T05:06:57.000Z","size":504,"stargazers_count":2,"open_issues_count":4,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-08T05:09:50.025Z","etag":null,"topics":["cli","firmware-upgrade","juniper","junos","junos-pyez","netconf","network-automation","network-engineering","pyez","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shigechika.png","metadata":{"files":{"readme":"README.ja.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-12-05T02:34:56.000Z","updated_at":"2026-05-08T03:03:08.000Z","dependencies_parsed_at":"2024-01-12T11:07:53.147Z","dependency_job_id":"920f63e3-960f-417b-bdb0-5fcfb654cb87","html_url":"https://github.com/shigechika/junos-ops","commit_stats":null,"previous_names":["shigechika/junos-ops"],"tags_count":45,"template":false,"template_full_name":null,"purl":"pkg:github/shigechika/junos-ops","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shigechika%2Fjunos-ops","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shigechika%2Fjunos-ops/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shigechika%2Fjunos-ops/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shigechika%2Fjunos-ops/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shigechika","download_url":"https://codeload.github.com/shigechika/junos-ops/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shigechika%2Fjunos-ops/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32770544,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-08T02:36:36.067Z","status":"ssl_error","status_checked_at":"2026-05-08T02:36:07.210Z","response_time":54,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","firmware-upgrade","juniper","junos","junos-pyez","netconf","network-automation","network-engineering","pyez","python"],"created_at":"2026-02-14T11:26:09.791Z","updated_at":"2026-05-08T07:04:55.293Z","avatar_url":"https://github.com/shigechika.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# junos-ops\n\n[![PyPI version](https://img.shields.io/pypi/v/junos-ops)](https://pypi.org/project/junos-ops/)\n[![CI](https://github.com/shigechika/junos-ops/actions/workflows/ci.yml/badge.svg)](https://github.com/shigechika/junos-ops/actions/workflows/ci.yml)\n[![Python](https://img.shields.io/pypi/pyversions/junos-ops)](https://pypi.org/project/junos-ops/)\n\n[English](https://github.com/shigechika/junos-ops/blob/main/README.md)\n\nJuniper/JUNOS デバイスの運用を NETCONF 経由で自動化する Python CLI です。モデル自動検出付きの upgrade、rollback、reboot、config push、RSI/SCF 収集をサポートします。\n\n\u003e **RSI/SCF とは？** RSI = `request support information`（JTAC 向けサポート情報スナップショット）、SCF = `show configuration | display set`。収集したファイルはそれぞれ `.rsi` / `.scf` 拡張子で保存されるため、本ツールでも略号でそのまま扱っています。\n\n## 特徴\n\n- デバイスモデルの自動検出とパッケージの自動マッピング\n- SCP 転送＋チェックサム検証による安全なパッケージコピー\n- インストール前のパッケージ検証（validate）\n- ロールバック対応（MX/EX/SRX モデル別処理）\n- スケジュールリブート（ファームウェアインストール後の config 変更を自動検出し、必要なら再インストール）\n- RSI（request support information）/ SCF（show configuration | display set）の並列収集\n- Pre-flight `check` サブコマンド: NETCONF 疎通・ローカル firmware ハッシュ（デバイス接続不要）・リモート firmware ハッシュを 1 コマンドで統合表示\n- 任意の CLI コマンドを複数ホストで実行（`show` サブコマンド、`RpcTimeoutError` 自動リトライ対応）\n- `config` での設定投入（commit confirmed + コミット後ヘルスチェック: ping / `uptime` NETCONF プローブ / 任意の CLI コマンド）\n- Jinja2 テンプレートによるホスト別設定生成（[詳細](docs/template.md#日本語版)）\n- `--tags` によるタグベースのホストフィルタ（AND マッチ）\n- ローカルファームウェア置き場（`lpath`、`~` 展開対応）\n- ドライランモード（`--dry-run`）で事前確認\n- ThreadPoolExecutor による並列実行（`--workers N`）\n- 設定ファイル（INI 形式）によるホスト・パッケージ管理\n\n## 目次\n\n- [インストール](#インストール)\n- [設定ファイル（config.ini）](#設定ファイルconfigini)\n- [使い方](#使い方)\n- [ワークフロー](#ワークフロー)\n- [実行例](#実行例)\n- [対応モデル](#対応モデル)\n- [License](#license)\n\n## インストール\n\n### Homebrew (macOS)\n\n```bash\nbrew install shigechika/tap/junos-ops\n```\n\n### Debian / Ubuntu (.deb)\n\nUbuntu 24.04 (Noble) 向けのパッケージを [GitHub Releases](https://github.com/shigechika/junos-ops/releases) で配布しています。`/opt/venvs/junos-ops/` に自己完結型の Python 仮想環境をインストールし、`/usr/bin/junos-ops` にシンボリックリンクを作成します。\n\n```bash\nsudo apt install ./junos-ops_*~noble.deb\n```\n\n### RHEL / Rocky Linux / AlmaLinux (.rpm)\n\nRHEL/Rocky/AlmaLinux 9 向けのパッケージを [GitHub Releases](https://github.com/shigechika/junos-ops/releases) で配布しています。Python 3.12 が必要です。\n\n```bash\nsudo dnf install python3.12\nsudo rpm -ivh junos-ops-*-1.el9.x86_64.rpm\n```\n\n### pip\n\n```bash\npip install junos-ops\n```\n\n最新版に更新する場合:\n\n```bash\npip install junos-ops --upgrade\n```\n\n### 開発用インストール\n\n```bash\ngit clone https://github.com/shigechika/junos-ops.git\ncd junos-ops\npython3 -m venv .venv\n. .venv/bin/activate\npip install -e \".[test]\"\n```\n\n### 依存ライブラリ\n\n- [junos-eznc (PyEZ)](https://www.juniper.net/documentation/product/us/en/junos-pyez) — Juniper NETCONF自動化ライブラリ\n- [looseversion](https://pypi.org/project/looseversion/) — バージョン比較\n\n### タブ補完（任意）\n\n```bash\npip install junos-ops[completion]\neval \"$(register-python-argcomplete junos-ops)\"\n```\n\n`eval` の行を `~/.bashrc` や `~/.zshrc` に追記すると常時有効になります。\n\n### pip3のインストール（未導入の場合）\n\n\u003cdetails\u003e\n\u003csummary\u003eOS別手順\u003c/summary\u003e\n\n- **Ubuntu/Debian**\n  ```bash\n  sudo apt install python3-pip\n  ```\n\n- **CentOS/RedHat**\n  ```bash\n  sudo dnf install python3-pip\n  ```\n\n- **macOS**\n  ```bash\n  brew install python3\n  ```\n\n\u003c/details\u003e\n\n## 設定ファイル（config.ini）\n\nINI形式の設定ファイルで、接続情報とモデル別パッケージを定義します。\n\n設定ファイルは以下の順序で探索されます（`-c` / `--config` で明示指定も可能）：\n\n1. カレントディレクトリの `./config.ini`\n2. `~/.config/junos-ops/config.ini`（XDG_CONFIG_HOME）\n\n### ログ設定（logging.ini）\n\n`logging.ini` を配置すると、ログ出力をカスタマイズできます（例: paramiko/ncclient の冗長なログを抑制）。`config.ini` と同じ順序で探索されます：\n\n1. カレントディレクトリの `./logging.ini`\n2. `~/.config/junos-ops/logging.ini`（XDG_CONFIG_HOME）\n\nどちらも見つからない場合は、デフォルトのログ設定（INFO レベル、stdout 出力）が使用されます。\n\n### DEFAULTセクション\n\n全ホスト共通の接続設定とモデル→パッケージマッピングを記述します。\n\n```ini\n[DEFAULT]\nid = exadmin          # SSHユーザ名\npw = password         # SSHパスワード\nsshkey = id_ed25519   # SSH秘密鍵ファイル\nport = 830            # NETCONFポート\nhashalgo = md5        # チェックサムアルゴリズム\nrpath = /var/tmp      # リモートパス\n# ssh_config = ~/.ssh/config    # OpenSSH 互換設定（ProxyCommand 等）。未指定時は PyEZ が ~/.ssh/config を自動参照\n# lpath = ~/firmware            # ローカルのファームウェア置き場（~ 展開対応、デフォルト: カレントディレクトリ）\n# huge_tree = true    # 大きなXMLレスポンスを許可\n# RSI_DIR = ./rsi/    # RSI/SCFファイルの出力先\n# DISPLAY_STYLE = display set   # SCF出力形式（デフォルト: display set）\n# DISPLAY_STYLE =               # 空にすると show configuration のみ（stanza形式）\n\n# モデル名.file = パッケージファイル名\n# モデル名.hash = チェックサム値\nEX2300-24T.file = junos-arm-32-18.4R3-S10.tgz\nEX2300-24T.hash = e233b31a0b9233bc4c56e89954839a8a\n```\n\nモデル名はデバイスから自動取得される`model`フィールドと一致させます。\n\n### ホストセクション\n\n各セクション名がホスト名になります。DEFAULTの値をホスト単位でオーバーライドできます。\n\n```ini\n[rt1.example.jp]             # セクション名がそのまま接続先ホスト名\ntags = tokyo, core           # タグベースのホストフィルタリング（--tags）\n[rt2.example.jp]\nhost = 192.0.2.1             # IPアドレスで接続先を指定\ntags = osaka, core\n[sw1.example.jp]\nid = sw1                     # 接続ユーザを変更\nsshkey = sw1_rsa             # SSH鍵を変更\nssh_config = ~/.ssh/config.lab   # ホスト別の OpenSSH 設定（bastion 等）\ntags = tokyo, access\n[sw2.example.jp]\nport = 10830                 # ポートを変更\n[sw3.example.jp]\nEX4300-32F.file = jinstall-ex-4300-20.4R3.8-signed.tgz   # このホストだけ別バージョン\nEX4300-32F.hash = 353a0dbd8ff6a088a593ec246f8de4f4\n```\n\n## 使い方\n\n```\njunos-ops \u003csubcommand\u003e [options] [hostname ...]\n```\n\n### サブコマンド一覧\n\n| サブコマンド | 説明 |\n|-------------|------|\n| `upgrade` | コピー＋インストールを一括実行 |\n| `copy` | ローカルからリモートへパッケージをコピー |\n| `install` | コピー済みパッケージをインストール |\n| `rollback` | 前バージョンにロールバック |\n| `version` | running/planning/pendingバージョンとリブート予定を表示 |\n| `reboot --at YYMMDDHHMM` | 指定日時にリブートをスケジュール |\n| `ls [-l]` | リモートパスのファイル一覧 |\n| `show COMMAND [--retry N]` / `show -f FILE` | 任意の CLI コマンド（またはコマンドファイル）を複数ホストで実行 |\n| `check [--connect\\|--local\\|--remote\\|--all] [--model M]` | Pre-flight チェック: NETCONF 疎通・ローカル/リモート firmware ハッシュ |\n| `config -f FILE` | set コマンドファイルを適用（`--confirm` / `--timeout` / `--no-confirm` / `--health-check` / `--no-health-check` の詳細は [docs/config.md](docs/config.md) を参照） |\n| `rsi` | RSI/SCF を並列収集 |\n| （なし） | デバイスファクト（device facts）を表示 |\n\n### 共通オプション\n\n| オプション | 説明 |\n|-----------|------|\n| `hostname` | 対象ホスト名（省略時は設定ファイル内の全ホスト） |\n| `-c`, `--config CONFIG` | 設定ファイル指定（デフォルト: `config.ini` → `~/.config/junos-ops/config.ini`） |\n| `-n`, `--dry-run` | テスト実行（接続とメッセージ出力のみ、実行しない） |\n| `-d`, `--debug` | デバッグ出力 |\n| `--force` | 条件を無視して強制実行 |\n| `--tags TAG[,TAG...]` | タグでホストをフィルタ。カンマ区切りは 1 グループ内の AND、`--tags` の繰り返しはグループ間 OR。ホスト名併記時はタグフィルタと積集合。詳細は「タグベースのホストフィルタリング」セクション参照 |\n| `--workers N` | 並列実行数（デフォルト: upgrade系=1, rsi=20） |\n| `--version` | プログラムバージョン表示 |\n\n## ワークフロー\n\n### CLI 処理フロー\n\nすべてのサブコマンドは共通の実行パイプラインを通ります。設定ファイルを読み込み、対象ホストを決定し（`--tags` で絞り込み可能）、`ThreadPoolExecutor` でホストごとにワーカースレッドへ振り分けます。`--workers N` で並列数を制御でき、upgrade 系はデフォルト 1（安全な逐次実行）、RSI 収集はデフォルト 20（I/O バウンドのため並列化が有効）です。各ワーカーは独立した NETCONF セッションを確立するため、ホスト間で状態を共有しません。\n\n```mermaid\nflowchart TD\n    A[junos-ops CLI] --\u003e B[config.ini 読み込み]\n    B --\u003e C[対象ホスト決定]\n    C --\u003e D{サブコマンド}\n    D --\u003e E[upgrade / copy / install]\n    D --\u003e F[version / rollback / reboot]\n    D --\u003e G[config / show / ls]\n    D --\u003e H[rsi]\n    D --\u003e I[\"（なし）→ facts\"]\n    E \u0026 F \u0026 G \u0026 H \u0026 I --\u003e J[\"ThreadPoolExecutor\u003cbr/\u003e--workers N\"]\n    J --\u003e K[\"NETCONF / SCP\u003cbr/\u003eホストごとに実行\"]\n    K --\u003e L[結果出力]\n```\n\n### JUNOS アップグレードワークフロー\n\nファームウェア更新はリスクを最小化する4ステップで構成されています。まず `dry-run` で接続性・パッケージの存在・チェックサムを変更なしで検証します。次に `upgrade` でコピーとインストールを実行します。`version` でインストール後の pending バージョンが想定通りか確認し、問題がなければリブートをスケジュールします。リブートを別ステップにしているのは、メンテナンスウィンドウを選択できるようにするためです。リブート前であればいつでも `rollback` で元のファームウェアに戻せます。\n\n```mermaid\nflowchart TD\n    A[\"1. 事前確認\u003cbr/\u003ejunos-ops upgrade -n\"] --\u003e B[\"2. アップグレード\u003cbr/\u003ejunos-ops upgrade\"]\n    B --\u003e C[\"3. バージョン確認\u003cbr/\u003ejunos-ops version\"]\n    C --\u003e D[\"4. リブート\u003cbr/\u003ejunos-ops reboot --at\"]\n    D -.-\u003e|\"問題発生時\"| E[\"ロールバック\u003cbr/\u003ejunos-ops rollback\"]\n```\n\n```\n1. dry-run で事前確認\n   junos-ops upgrade --dry-run hostname\n\n2. upgrade でコピー＋インストール\n   junos-ops upgrade hostname\n\n3. version でバージョン確認\n   junos-ops version hostname\n\n4. reboot でリブート日時を指定\n   junos-ops reboot --at 2506130500 hostname\n```\n\n問題が発生した場合は `rollback` で前バージョンに戻せます。\n\n### upgrade 内部フロー\n\n`upgrade` サブコマンドは更新前後に複数の安全チェックを行います。まず実行中バージョンと目標バージョンを比較し、一致していればスキップします。異なる pending バージョンが存在する場合は先にロールバックしてから進行します。コピーフェーズではディスク容量を確保（ストレージ cleanup + EX/QFX ではスナップショット削除）し、`safe_copy` でチェックサム検証付きの転送を行い破損を検出します。インストール前に既存のリブートスケジュールを解除し、rescue config を復旧基点として保存します。最後に `sw.install()` がデバイス上でパッケージの整合性を検証してから適用します。\n\n```mermaid\nflowchart TD\n    A[NETCONF 接続] --\u003e B{\"実行中バージョン\u003cbr/\u003e= 目標?\"}\n    B --\u003e|yes| C([スキップ — 更新不要])\n    B --\u003e|no| D{\"pending バージョン\u003cbr/\u003eあり?\"}\n    D --\u003e|no| E[copy]\n    D --\u003e|yes| F{pending ≥ 目標?}\n    F --\u003e|yes, --force なし| C\n    F --\u003e|no / --force| G[pending をロールバック]\n    G --\u003e E\n\n    subgraph copy [\"copy()\"]\n        E --\u003e H[ストレージ cleanup]\n        H --\u003e I[\"スナップショット削除\u003cbr/\u003e(EX/QFX のみ)\"]\n        I --\u003e J[\"safe_copy（SCP 転送）\u003cbr/\u003e+ チェックサム検証\"]:::safe\n    end\n\n    J --\u003e K[リブートスケジュール解除]\n    K --\u003e L[rescue config 保存]:::safe\n    L --\u003e M[\"sw.install()\u003cbr/\u003evalidate + チェックサム検証\"]:::install\n    M --\u003e N([完了 — リブート待ち])\n\n    classDef safe fill:#d4edda,stroke:#28a745,color:#000\n    classDef install fill:#cce5ff,stroke:#007bff,color:#000\n```\n\n### reboot 安全フロー\n\n`reboot` はリブートスケジュール設定前に、ファームウェアインストール後に設定変更がなかったかを自動検出します。変更があった場合は rescue config を再保存し、validation 付きで再インストールを行い、新ファームウェアと現在の設定の互換性を確認します。\n\n```mermaid\nflowchart TD\n    A[NETCONF 接続] --\u003e B{\"既存リブート\u003cbr/\u003eスケジュールあり?\"}\n    B --\u003e|no| D\n    B --\u003e|yes| C{--force?}\n    C --\u003e|no| B2([スキップ — 既存スケジュール維持])\n    C --\u003e|yes| CL[既存スケジュール解除] --\u003e D\n\n    D{\"pending バージョン\u003cbr/\u003eあり?\"} --\u003e|no| SCH\n    D --\u003e|yes| E[最終コミット時刻を取得]\n    E --\u003e F[rescue config 時刻を取得]\n    F --\u003e G{\"インストール後に\u003cbr/\u003e設定変更あり?\"}\n    G --\u003e|no| SCH\n    G --\u003e|yes| H[rescue config 再保存]:::warned\n    H --\u003e I[\"ファームウェア再インストール\u003cbr/\u003e（validate + チェックサム検証）\"]:::install\n    I --\u003e|成功| SCH\n    I --\u003e|失敗| ERR([中止 — リブートしない]):::errstyle\n\n    SCH[\"リブートスケジュール設定\u003cbr/\u003e--at YYMMDDHHMM\"]:::safe\n\n    classDef safe fill:#d4edda,stroke:#28a745,color:#000\n    classDef install fill:#cce5ff,stroke:#007bff,color:#000\n    classDef warned fill:#fff3cd,stroke:#ffc107,color:#000\n    classDef errstyle fill:#f8d7da,stroke:#dc3545,color:#000\n```\n\n### config 適用ワークフロー\n\n`config` サブコマンドは安全なコミットフローを採用しています。`commit confirmed`（自動ロールバックタイマー） → **ヘルスチェック** → `commit`（確定）の順に実行します。ヘルスチェックが失敗した場合、最終 `commit` を送信せず、タイマー満了時に JUNOS が自動的にロールバックします。\n\nヘルスチェック（`uptime`、ping、CLI コマンド）、commit confirmed フロー、`--no-confirm`、並列実行などの詳細は [docs/config.ja.md](docs/config.ja.md) を参照してください。\n\n```\n1. dry-run で差分を確認\n   junos-ops config -f commands.set --dry-run hostname\n\n2. 適用\n   junos-ops config -f commands.set hostname\n\n3. NETCONF ヘルスチェックで適用（ping 不要）\n   junos-ops config -f commands.set --health-check uptime hostname\n```\n\n### タグベースのホストフィルタリング\n\n`--tags` で `config.ini` に定義したタグによりホストを絞り込めます。2 種類の演算子を組み合わせて柔軟に選択できます。\n\n- **グループ内は AND**: `--tags` の値をカンマ区切りにすると、そのすべてのタグを持つホストだけが対象になります（`--tags tokyo,core` → tokyo と core を**両方**持つホスト）。\n- **グループ間は OR**: `--tags` を複数回指定するとそれぞれがグループになり、**いずれか**を満たせばマッチします（`--tags main --tags backup` → main か backup のどちらかを持つホスト）。\n- **ホスト名併記は AND（積集合）**: 明示ホスト名と組み合わせた場合、タグで絞ったうえで名前リストとの積集合を取ります。「タグ条件を満たすホストのうち、さらに名前で絞り込む」動作です。\n\n論理式で書くと `(--tags group₁) OR (--tags group₂) OR …` でホスト集合を絞り、ホスト名リストがあればさらに `AND` で交差させる形になります。`check` で bad だった数台だけを `--tags backup` の安全柵を残したまま再 copy する、といった使い方に向きます。\n\n\u003e **履歴:**\n\u003e v0.16.3 以前は `--tags` + ホスト名を和集合として扱っていました。v0.16.4 で積集合に変更し、`--tags` を「さらに名前で絞り込む」安全フィルタとして読ませています。v0.16.6 で `--tags` を繰り返し指定可能にしてグループ間 OR を追加しました（それ以前は argparse の仕様で最後の `--tags` しか効かず、黙って上書きされていました）。\n\n```\n# tokyo タグを持つ全ホスト\njunos-ops version --tags tokyo\n\n# tokyo AND core の両方のタグを持つホスト\njunos-ops version --tags tokyo,core\n\n# main または backup のどちらかのタグを持つホスト\njunos-ops check --remote --tags main --tags backup\n\n# (tokyo AND core) OR access — tokyo かつ core、または access タグを持つホスト\njunos-ops version --tags tokyo,core --tags access\n\n# backup タグを持つホストのうち、指定した 2 台だけを対象にする（タグフィルタ ∩ 名前リスト）\njunos-ops copy --tags backup rt1.example.jp rt2.example.jp\n```\n\n## 実行例\n\n### upgrade（パッケージ更新）\n\n```\n% junos-ops upgrade rt1.example.jp\n# rt1.example.jp\nremote: jinstall-ppc-18.4R3-S10-signed.tgz is not found.\ncopy: system storage cleanup successful\nrt1.example.jp: cleaning filesystem ...\nrt1.example.jp: b'jinstall-ppc-18.4R3-S10-signed.tgz': 380102074 / 380102074 (100%)\nrt1.example.jp: checksum check passed.\ninstall: clear reboot schedule successful\ninstall: rescue config save successful\nrt1.example.jp: software validate package-result: 0\n```\n\n### version（バージョン確認）\n\n```\n% junos-ops version rt1.example.jp\n# rt1.example.jp\n  - hostname: rt1\n  - model: MX5-T\n  - running version: 18.4R3-S7.2\n  - planning version: 18.4R3-S10\n    - running='18.4R3-S7.2' \u003c planning='18.4R3-S10'\n  - pending version: 18.4R3-S10\n    - running='18.4R3-S7.2' \u003c pending='18.4R3-S10' : Please plan to reboot.\n  - reboot requested by exadmin at Sat Dec  4 05:00:00 2021\n```\n\n### check（Pre-flight 検証）\n\nNETCONF 疎通、ローカル/リモートの firmware ハッシュを 1 コマンドで一括検証します。1 件でも失敗すると終了コードが非ゼロになります。フラグ未指定時のデフォルトは `--connect` のみ。\n\n`--local` は **インベントリモード** で、ホスト名は無視されます。`config.ini` に記載された `\u003cmodel\u003e.file` / `\u003cmodel\u003e.hash` のペアを列挙してステージングサーバー上のファイルを検証するので、NETCONF 接続は一切不要です:\n\n```\n% junos-ops check --local\nmodel            file                                                        status      local_file\n---------------  ----------------------------------------------------------  ----------  ----------------------------------------------------------------------\nex2300-24t       junos-arm-32-23.4R2-S7.4.tgz                                ok          /opt/firmware/junos-arm-32-23.4R2-S7.4.tgz\nex3400-24t       junos-arm-32-23.4R2-S7.4.tgz                                ok(cached)  /opt/firmware/junos-arm-32-23.4R2-S7.4.tgz\nex4300-32f       jinstall-ex-4300-21.4R3-S12.2-signed.tgz                    ok          /opt/firmware/jinstall-ex-4300-21.4R3-S12.2-signed.tgz\nmx5-t            jinstall-ppc-21.2R3-S8.5-signed.tgz                         missing     /opt/firmware/jinstall-ppc-21.2R3-S8.5-signed.tgz\n\n  mx5-t: - local package: /opt/firmware/jinstall-ppc-21.2R3-S8.5-signed.tgz is not found.\n```\n\n`--model M` で特定モデルだけに絞り込むことも可能です。\n\n`--connect` / `--remote`（および `--all`）は **ホスト単位** で、指定されたホスト（または `config.ini` 内の全ホスト、`--tags` でフィルタ可能）に対して動作します。`--remote` は `copy` 完了後・`install` 前の「SCP が最後まで落ちたか」確認としても使えます:\n\n```\n% junos-ops check --connect --remote rt1.example.jp rt2.example.jp\nhostname         connect  remote      model     file\n---------------  -------  ----------  --------  -----------------------------------\nrt1.example.jp   ok       ok          MX5-T     jinstall-ppc-18.4R3-S10-signed.tgz\nrt2.example.jp   ok       missing     MX5-T     jinstall-ppc-18.4R3-S10-signed.tgz\n\n  rt2.example.jp: remote: - remote package: jinstall-ppc-18.4R3-S10-signed.tgz is not found.\n```\n\n`--connect` / `--remote` でモデルが必要な場面では、`--model` 引数、`config.ini` の host セクションの `model = MX5-T` キー、デバイスから取得した `facts[\"model\"]` の順にフォールバックします。\n\n`--all` は両方のテーブルを順に出力します（先にインベントリ、次にホスト別）。\n\n### rsi（RSI/SCF並列収集）\n\n```\n% junos-ops rsi --workers 5 rt1.example.jp rt2.example.jp\n# rt1.example.jp\n  rt1.example.jp.SCF done\n  rt1.example.jp.RSI done\n# rt2.example.jp\n  rt2.example.jp.SCF done\n  rt2.example.jp.RSI done\n```\n\n### reboot（スケジュールリブート）\n\n```\n% junos-ops reboot --at 2506130500 rt1.example.jp\n# rt1.example.jp\n\tShutdown at Fri Jun 13 05:00:00 2025. [pid 97978]\n```\n\n### config（set コマンドファイル適用）\n\nset 形式のコマンドファイルを複数デバイスに適用します。commit check → commit confirmed → confirm の安全なコミットフローで実行します。\n\n```\n% cat add-user.set\nset system login user viewer class read-only\nset system login user viewer authentication ssh-ed25519 \"ssh-ed25519 AAAA...\"\n\n% junos-ops config -f add-user.set --dry-run rt1.example.jp rt2.example.jp\n# rt1.example.jp\n[edit system login]\n+    user viewer {\n+        class read-only;\n+        authentication {\n+            ssh-ed25519 \"ssh-ed25519 AAAA...\";\n+        }\n+    }\n\tdry-run: rollback (no commit)\n# rt2.example.jp\n\t...\n\n% junos-ops config -f add-user.set rt1.example.jp rt2.example.jp\n# rt1.example.jp\n\t...\n\tcommit check passed\n\tcommit confirmed 1 applied\n\thealth check: uptime (NETCONF RPC)\n\thealth check passed (uptime: 2026-04-16 13:20:31 JST)\n\tcommit confirmed, changes are now permanent\n# rt2.example.jp\n\t...\n```\n\n`--confirm N` で commit confirmed のタイムアウトを変更できます（デフォルト: 1分）。`--no-health-check` でコミット後のヘルスチェックをスキップできます。\n\nset ファイルには `#` コメント行や空行を含めることができます。適用前に自動的に除去されます。\n\n#### Jinja2 テンプレート\n\n`.j2` ファイルを使って、1つのテンプレートからホストごとに異なる設定を生成できます。変数は config.ini の `var_*` キーとデバイスファクトから取得されます。\n\n```bash\njunos-ops config -f ntp.set.j2 --dry-run rt1.example.jp sw1.example.jp\njunos-ops config -f ntp.set.j2 rt1.example.jp sw1.example.jp\n```\n\n条件分岐やループなど詳しい使い方は [docs/template.ja.md](docs/template.ja.md) を参照してください。\n\n### show（CLI コマンド実行）\n\n任意の CLI コマンドを複数デバイスに対して並列実行します。`--retry N` で `RpcTimeoutError` 発生時に自動リトライできます（大量ホストへの一括実行時に有効）。\n\n```\n% junos-ops show \"show bgp summary\" --config accounts.ini gw1.example.jp gw2.example.jp\n# gw1.example.jp\nGroups: 4 Peers: 6 Down peers: 0\n...\n# gw2.example.jp\nGroups: 3 Peers: 4 Down peers: 0\n...\n```\n\n`-f` でファイルから複数コマンドを読み込み、デバイスごとに1つの NETCONF セッション内で順次実行します。\n\n```\n% cat commands.txt\n# セキュリティポリシー確認\nshow security policies hit-count\nshow security flow session summary\n\n% junos-ops show -f commands.txt --config accounts.ini fw1.example.jp\n# fw1.example.jp\n## show security policies hit-count\n...\n\n## show security flow session summary\n...\n```\n\n`--retry N` で `RpcTimeoutError` 時に自動リトライします（バックオフ: 5秒, 10秒, 15秒, ...）:\n\n```\n% junos-ops show \"show system alarms\" --retry 2 --workers 10 --config accounts.ini\n```\n\n#### 構造化出力（`--format`）\n\n`-F` / `--format {text,json,xml}` で出力形式を切り替えられます。`text` が既定（従来動作）、`json` はプログラム／AI アシスタント向け、`xml` は RPC 応答を pretty-print して返します。\n\n```\n% junos-ops show \"show interfaces terse\" --format json gw1.example.jp\n# gw1.example.jp\n## show interfaces terse\n{\n  \"interface-information\": {\n    \"physical-interface\": [ ... ]\n  }\n}\n```\n\n\u003e **注意 — `json` / `xml` ではパイプ段が落ちる。** NETCONF 経由で `json`／`xml` を要求すると、`| match`、`| last`、`| count` などのパイプ修飾子はデバイス側で暗黙に落とされます（[Juniper/junos-mcp-server#4](https://github.com/Juniper/junos-mcp-server/issues/4)／[#12](https://github.com/Juniper/junos-mcp-server/issues/12) 参照）。`--format text` なら従来どおりパイプ段は有効です。構造化出力をフィルタしたいときは `text` のままシェル側（`jc` / `grep` / 後段の `jq` 等）で加工するか、対応する RPC を直接呼び出してください。\n\n### 引数なし（デバイスファクト表示）\n\n```\n% junos-ops gw1.example.jp\n# gw1.example.jp\n{'2RE': True,\n 'hostname': 'gw1',\n 'model': 'MX240',\n 'version': '18.4R3-S7.2',\n ...}\n```\n\n## 対応モデル\n\n設定ファイルでモデル名とパッケージファイルを定義することで、任意のJuniperモデルに対応できます。設定例に含まれるモデル:\n\n| シリーズ | モデル例 |\n|---------|---------|\n| EX | EX2300-24T, EX3400-24T, EX4300-32F |\n| MX | MX5-T, MX240 |\n| QFX | QFX5110-48S-4C |\n| SRX | SRX300, SRX345, SRX1500, SRX4600 |\n\n## License\n\n[Apache License 2.0](LICENSE)\n\nCopyright 2022-2025 AIKAWA Shigechika\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshigechika%2Fjunos-ops","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshigechika%2Fjunos-ops","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshigechika%2Fjunos-ops/lists"}