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

我觉得要是能自动化,就不用每次都麻烦地打开环境设置来改路由器号码了…然后也不会每次都忘记,然后一直问自己“为什么不能连接?”。
我在工作中没有直接使用过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的文件中,必要的项目有以下两个。
Ansible中有很多模块,可以通过调用它们并传递参数(即右侧的冒号后面)来执行操作。参数是必需的。
在编程语言中,我们也会调用函数并传递参数来执行操作,从形象上来说,模块≒函数,参数≒参数,大概就是这样的概念了。
模块是playbook的最小单位,而任务则像是包含模块的盒子。
由于在demo1.yml中的hosts字段中指定了localhost,因此模块将在localhost上运行。
在tasks字段中,将字符串“执行whoami命令”作为参数传递给任务名称,并将’whoami’作为参数传递给shell模块以执行命令。
我会尝试运行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运算符。
请您参考官方网站以获取详细信息。
网络设置的命令如下:
% ./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
现在只需双击文件即可切换!

请看
【提示】Ansible工作手册
【提示】MacBook互联网连接方法”有线/无线(WiFi)支持”【networksetup命令篇】
介绍Mac的Wifi命令
剧本基础
在macOS上通过双击图标启动shell脚本
结束时
Ansible被广泛认为有学习成本低的优点,确实,YAML格式的文件容易上手,而且能够快速自动化。虽然这次我们只是进行了简单的网络切换,但是我仍然觉得使用Ansible进行自动化非常方便,因此我想更深入地学习一下。希望对想尝试一下Ansible的人有所帮助。