我尝试使用Ansible自动化网络设置的切换

首先

在家工作或上班时,由于工作环境的变化,必须更改网络设置。
具体来说,在办公室,使用DHCP服务器自动分配的路由器IP地址可以连接到网络没有问题,但在家的网络环境下,如果从使用DHCP服务器自动分配的路由器IP地址连接,会遵循下图中的蓝线导致VPN连接被阻断,所以需要手动切换到192.168.11.2。

home-network-image.png

我觉得要是能自动化,就不用每次都麻烦地打开环境设置来改路由器号码了…然后也不会每次都忘记,然后一直问自己“为什么不能连接?”。

我在工作中没有直接使用过Ansible,但是在项目中它被使用过,所以我对它的存在有所了解,并且因为它的学习成本低,容易入手,所以这次我决定尝试使用它。
平时我主要使用Vue.js和Laravel,所以我试图将其与这些语言进行类比来理解。

Ansible是一种工具。

我从Red Hat的官方文档中引用了这段话。

Ansible® 是一個開源的IT自動化工具,專門用於自動化供應、配置管理、應用部署、協調以及其他許多IT流程。與其他簡單管理工具不同,Ansible的使用者(系統管理員、開發者、架構師等)可以利用Ansible的自動化功能來進行軟體安裝、常規任務自動化、基礎設施供應、提升安全與合規性、系統修補、以及組織內自動化的分享。

原网址:什么是Ansible

听起来有点复杂,但总的来说,使用Ansible可以自动化安装软件包和环境配置,无论谁执行多少次,都能保证达到相同的状态(据说这就是幂等性)。这是我对它的大致理解。

环境

macOS Monterey版本12.4
ansible [核心2.13.6]

使用方法

首先,使用Homebrew安装Ansible。

% brew install ansible

让我们检查一下版本,看看是否正确显示。

ansible --version

在Ansible中,我们按照顺序将要执行的操作写入名为Playbook(剧本)的YAML格式文件中。

首先,创建一个名为demo1.yml的文件,然后在终端中执行whoami命令。
以下是一个几乎最小结构的Playbook文件。

---
- hosts: localhost
  tasks:
    - name: whoamiコマンドを実行する 
      shell: whoami 

在第一行中,声明了它是yml格式。

在Playbook的文件中,必要的项目有以下两个。

名称説明hostsモジュールをどの環境で実行するか指定(実行対象)tasksモジュールを呼び出して実際に実行するさまざまな処理を書いていく

Ansible中有很多模块,可以通过调用它们并传递参数(即右侧的冒号后面)来执行操作。参数是必需的。
在编程语言中,我们也会调用函数并传递参数来执行操作,从形象上来说,模块≒函数,参数≒参数,大概就是这样的概念了。
模块是playbook的最小单位,而任务则像是包含模块的盒子。

由于在demo1.yml中的hosts字段中指定了localhost,因此模块将在localhost上运行。
在tasks字段中,将字符串“执行whoami命令”作为参数传递给任务名称,并将’whoami’作为参数传递给shell模块以执行命令。

名称役割nameタスク名を指定するshellパラメータで渡されたLinuxコマンドを実行する

我会尝试运行demo1.yml。以下是Playbook执行的命令。

% ansible-playbook demo1.yml

执行结果

% ansible-playbook demo1.yml      
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [localhost] **************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************
ok: [localhost]

TASK [whoamiコマンドを実行する] ***********************************************************************************************************
changed: [localhost]

PLAY RECAP ********************************************************************************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

处理已顺利通过?

切换网络设置

现在,我们开始谈论正题,即网络切换。

作为步骤,
1. 获取当前使用的网络名称(SSID)
2-1. 如果它是家庭VPN可连接的SSID,则将IPv4设置为“手动输入”,并指定IPv4地址、子网掩码和路由器号码。
2-2. 如果是其他网络(如公司网络),则将IPv4设置更改为“使用DHCP服务器”。

要获取SSID信息,请使用以下命令。

% networksetup -getairportnetwork [ネットワークインターフェイス名]

执行以下命令可以显示网络接口的列表,事先查找并记录网络接口名称。(以下将使用en0作为示例。)

% networksetup -listallhardwareports

想要根据SSID更改设置是一种条件分支,因此需要将获取的信息存入变量中。
在Ansible中,您可以使用register命令将执行结果注册到变量中。

用Ansible编写如下:

---
- hosts: localhost
  tasks:
    - name: airportnetworknameを取得する
      shell: networksetup -getairportnetwork en0
      register: return_airport_network_name

当只有这么一句话的时候,在执行时无法显示return_airport_network_name的内容以进行确认,因此使用debug模块来显示。将msg作为参数传递,将输出自定义消息。
在末尾的.stdout处显示了shell的标准输出。
当想要获取数组中特定的一个元素时,可以类似于指定索引$array[0]的感觉。

- name: 取得したairportnetworknameを表示
      debug:
        msg: "{{ return_airport_network_name.stdout }}"

执行结果

% ansible-playbook change-setting-ipv4.yml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [localhost] **************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************
ok: [localhost]

TASK [airportnetworknameを取得する] *******************************************************************************************************
changed: [localhost]

TASK [取得したairportnetworknameを表示] ***************************************************************************************************
ok: [localhost] => {
    "msg": "Current Wi-Fi Network: hogehoge"
}

现在已经收集到所需要的信息,接下来就是进入条件分支了。

当在条件分支中使用

Ansible的条件分支使用when关键字。
这次的条件是检查return_airport_network_name.stdout中是否包含hogehoge,所以使用in运算符。

演算子説明A in [X, Y, Z]A と同じ値が X, Y, Z の中にあるときA not in [X, Y, Z]A と同じ値が X, Y, Z の中にないとき

请您参考官方网站以获取详细信息。

网络设置的命令如下:

% ./networksetup -setmanual <ネットワークサービスのデバイス名> <IPアドレス> <サブネットマスク> <ルーターのIPアドレス>
% ./networksetup -setdhcp <ネットワークサービスのデバイス名>

这样写成的话,就是用Ansible。

    - name: hogehogeならルーターを192.168.11.2に切り替える
      shell: networksetup -setmanual qnoteWi-fi 192.168.11.14 255.255.255.0 192.168.11.2
      when: "hogehoge" in return_airport_network_name.stdout
  
    - name: それ以外の場合はDHCPサーバーを使用する
      shell: networksetup -setdhcp qnoteWi-fi
      when: "hogehoge" not in return_airport_network_name.stdout

现在,我们已经能够写出一套基本的处理方法了。然而,由于设备名称和地址被硬编码到代码中,这样不便于管理,我们需要将其变量化以方便管理。

将变量放入另一个文件中

这次我们将在与change-setting-ipv4.yml相同的目录中创建vars.yml文件。

变量的声明非常简单,只需要在左边写键(key),右边写值(value)。这样就定义了一个可供引用的变量。

---

home:
  network:
    devicename: qnoteWi-fi
    name: hogehoge 
    ipv4address: 192.168.11.14
    subnetmask: 255.255.255.0
    router: 192.168.11.2

为了在change-setting-ipv4.yml中使用在vars.yml中定义的变量,将vars_file:写入hosts下以调用外部文件。

在Ansible中,当引用变量时,需要使用{{}}进行括起来。
然而,在when语句中,不需要使用{{}}进行括起来,直接写下变量即可识别为变量。(如果用花括号括起来会出错。)

---
- hosts: localhost
  vars_files:
    - ./vars.yml
  connection: local
  become: no
  tasks:
    - name: airportnetworknameを取得する
      shell: networksetup -getairportnetwork en0
      register: return_airport_network_name
      
    - name: 取得したairportnetworknameを表示
      debug:
        msg: "{{ return_airport_network_name.stdout }}"

    - name: "{{ home.network.name }}ならルーターを{{ home.network.router }}に切り替える"
      shell: networksetup -setmanual {{ home.network.devicename }} {{ home.network.ipv4address }} {{ home.network.subnetmask }} {{ home.network.router }}
      when: home.network.name in return_airport_network_name.stdout
  
    - name: それ以外の場合はDHCPサーバーを使用する
      shell: "networksetup -setdhcp {{ home.network.devicename }}"
      when: home.network.name not in return_airport_network_name.stdout

最后,添加connection插件和become指令,使文件更符合要求。

第5行的connection指定了连接方式,像这样写的话,这个Playbook一定会在本地环境中执行。(这样可以防止在其他环境中执行。)

第6行的 “become” 是指权限提升,它控制着是否可以以管理员权限用户身份执行Playbook。
在本次情况下,由于不需要是管理员权限用户,所以设为no。

这样一来,Playbook和变量文件就完成了?

% ansible-playbook change-setting-ipv4.yml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [localhost] **************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************
ok: [localhost]

TASK [airportnetworknameを取得する] *******************************************************************************************************
changed: [localhost]

TASK [取得したairportnetworknameを表示] ***************************************************************************************************
ok: [localhost] => {
    "msg": "Current Wi-Fi Network: hogehoge"
}

TASK [hogehogeならルーターを192.168.11.2に切り替える] *******************************************************************************
changed: [localhost]

TASK [それ以外の場合はDHCPサーバーを使用する] *********************************************************************************************
skipping: [localhost]

PLAY RECAP ********************************************************************************************************************************
localhost                  : ok=4    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0  

现在我正在打开终端并输入ansible执行命令,但是既然已经自动化了,我希望能够更简单地使用它。

因为不能通过双击打开Playbook文件,所以我们要创建一个只包含命令 ansible-playbook change-setting-ipv4.yml 的shell脚本文件。在MacOS中,如果将扩展名改为.command,就可以通过双击来运行它,所以我们要创建一个以以下名字命名的文件。

% touch change-setting-network.command

为了给予执行权限,请输入以下命令。

chmod +x change-setting-network.command

现在只需双击文件即可切换!

ezgif.com-gif-maker (3).gif

请看

【提示】Ansible工作手册
【提示】MacBook互联网连接方法”有线/无线(WiFi)支持”【networksetup命令篇】
介绍Mac的Wifi命令
剧本基础
在macOS上通过双击图标启动shell脚本

结束时

Ansible被广泛认为有学习成本低的优点,确实,YAML格式的文件容易上手,而且能够快速自动化。虽然这次我们只是进行了简单的网络切换,但是我仍然觉得使用Ansible进行自动化非常方便,因此我想更深入地学习一下。希望对想尝试一下Ansible的人有所帮助。

bannerAds