mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/yunionio/cloudpods.git
synced 2026-09-21 00:24:07 +08:00
368 lines
9.6 KiB
Go
368 lines
9.6 KiB
Go
// Copyright 2019 Yunion
|
|
//
|
|
// Licensed 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 models
|
|
|
|
import (
|
|
"encoding/json"
|
|
"encoding/xml"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"yunion.io/x/onecloud/pkg/util/ansiblev2"
|
|
)
|
|
|
|
func (router *SRouter) ansibleHost() (*ansiblev2.Host, error) {
|
|
vars := map[string]interface{}{
|
|
"ansible_user": router.User,
|
|
"ansible_host": router.Host,
|
|
}
|
|
if router.User != "root" {
|
|
vars["ansible_become"] = "yes"
|
|
}
|
|
if router.PrivateKey != "" {
|
|
vars["ansible_ssh_private_key_file"] = ".id_rsa"
|
|
}
|
|
if router.RealizeWgIfaces {
|
|
if err := router.inventoryWireguardVars(vars); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
h := ansiblev2.NewHost()
|
|
h.Vars = vars
|
|
return h, nil
|
|
}
|
|
|
|
func (router *SRouter) playFiles() map[string]string {
|
|
r := map[string]string{
|
|
"wgX.conf.j2": wgX_conf_j2,
|
|
}
|
|
if router.PrivateKey != "" {
|
|
r[".id_rsa"] = router.PrivateKey
|
|
}
|
|
return r
|
|
}
|
|
|
|
func (router *SRouter) playFilesStr() string {
|
|
files := router.playFiles()
|
|
r, _ := json.Marshal(files)
|
|
return string(r)
|
|
}
|
|
|
|
func (router *SRouter) inventoryWireguardVars(vars map[string]interface{}) error {
|
|
type (
|
|
WgNetworks []string
|
|
WgInterface map[string]interface{}
|
|
WgPeer map[string]interface{}
|
|
WgPeers map[string]WgPeer
|
|
)
|
|
ifaces, err := IfaceManager.getByRouter(router)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
wgnetworks := WgNetworks{}
|
|
for i := range ifaces {
|
|
iface := &ifaces[i]
|
|
if iface.PrivateKey == "" {
|
|
continue
|
|
}
|
|
ifacePeers, err := IfacePeerManager.getByIface(iface)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
wgpeers := WgPeers{}
|
|
for j := range ifacePeers {
|
|
ifacePeer := &ifacePeers[j]
|
|
if ifacePeer.PublicKey == "" {
|
|
continue
|
|
}
|
|
wgpeer := WgPeer{
|
|
"public_key": ifacePeer.PublicKey,
|
|
"allowed_ips": ifacePeer.AllowedIPs,
|
|
"endpoint": ifacePeer.Endpoint,
|
|
}
|
|
if ifacePeer.PersistentKeepalive > 0 {
|
|
wgpeer["persistent_keepalive"] = ifacePeer.PersistentKeepalive
|
|
}
|
|
wgpeers[ifacePeer.Name] = wgpeer
|
|
}
|
|
if len(wgpeers) == 0 {
|
|
continue
|
|
}
|
|
vars["wireguard_"+iface.Ifname+"_interface"] = WgInterface{
|
|
"private_key": iface.PrivateKey,
|
|
"listen_port": iface.ListenPort,
|
|
}
|
|
vars["wireguard_"+iface.Ifname+"_peers"] = wgpeers
|
|
wgnetworks = append(wgnetworks, iface.Ifname)
|
|
}
|
|
vars["wireguard_networks"] = wgnetworks
|
|
return nil
|
|
}
|
|
|
|
func (router *SRouter) playInstallWireguard() *ansiblev2.Play {
|
|
play := ansiblev2.NewPlay(
|
|
&ansiblev2.Task{
|
|
Name: "Enable EPEL",
|
|
ModuleName: "package",
|
|
ModuleArgs: map[string]interface{}{
|
|
"name": "epel-release",
|
|
"state": "present",
|
|
},
|
|
},
|
|
&ansiblev2.Task{
|
|
Name: "Check existence of wireguard repo file",
|
|
ModuleName: "stat",
|
|
ModuleArgs: map[string]interface{}{
|
|
"path": "/etc/yum.repos.d/_copr_jdoss-wireguard.repo",
|
|
},
|
|
Register: "wireguard_repo",
|
|
},
|
|
&ansiblev2.Task{
|
|
Name: "Enable wireguard repo from copr",
|
|
ModuleName: "get_url",
|
|
ModuleArgs: map[string]interface{}{
|
|
"dest": "/etc/yum.repos.d/_copr_jdoss-wireguard.repo",
|
|
"url": "https://copr.fedorainfracloud.org/coprs/jdoss/wireguard/repo/epel-7/jdoss-wireguard-epel-7.repo",
|
|
},
|
|
When: "(not wireguard_repo.stat.exists) or (wireguard_repo.stat.size < 10)",
|
|
},
|
|
&ansiblev2.Task{
|
|
Name: "Install wireguard packages",
|
|
ModuleName: "package",
|
|
ModuleArgs: map[string]interface{}{
|
|
"name": "{{ item }}",
|
|
"state": "present",
|
|
},
|
|
WithPlugin: "items",
|
|
WithPluginVal: []string{"wireguard-dkms", "wireguard-tools"},
|
|
},
|
|
&ansiblev2.Task{
|
|
Name: "Create /etc/wireguard",
|
|
ModuleName: "file",
|
|
ModuleArgs: map[string]interface{}{
|
|
"path": "/etc/wireguard",
|
|
"state": "directory",
|
|
"owner": "root",
|
|
"group": "root",
|
|
},
|
|
},
|
|
)
|
|
play.Hosts = "all"
|
|
play.Name = "Install WireGuard"
|
|
return play
|
|
}
|
|
|
|
func (router *SRouter) playDeployWireguardNetworks() *ansiblev2.Play {
|
|
play := ansiblev2.NewPlay(
|
|
&ansiblev2.ShellTask{
|
|
Name: "List existing managed wireguard networks",
|
|
Script: `grep -rnl 'Ansible managed' /etc/wireguard/ | grep '\.conf$' | cut -d/ -f4 | cut -d. -f1`,
|
|
Register: "oldconfs",
|
|
IgnoreErrors: true,
|
|
},
|
|
&ansiblev2.Task{
|
|
Name: "Backup stale wireguard confs",
|
|
ModuleName: "copy",
|
|
ModuleArgs: map[string]interface{}{
|
|
"src": "/etc/wireguard/{{ item }}.conf",
|
|
"dest": "/etc/wireguard/{{ item }}.conf.stale",
|
|
"remote_src": "yes",
|
|
},
|
|
WithPlugin: "items",
|
|
WithPluginVal: "{{ oldconfs.stdout_lines }}",
|
|
When: "(not oldconfs.failed) and (item not in wireguard_networks)",
|
|
},
|
|
&ansiblev2.Task{
|
|
Name: "Remove stale wireguard confs",
|
|
ModuleName: "file",
|
|
ModuleArgs: map[string]interface{}{
|
|
"path": "/etc/wireguard/{{ item }}.conf",
|
|
"state": "absent",
|
|
},
|
|
WithPlugin: "items",
|
|
WithPluginVal: "{{ oldconfs.stdout_lines }}",
|
|
When: "(not oldconfs.failed) and (item not in wireguard_networks)",
|
|
},
|
|
&ansiblev2.Task{
|
|
Name: "Disable stale wireguard networks",
|
|
ModuleName: "service",
|
|
ModuleArgs: map[string]interface{}{
|
|
"name": "wg-quick@{{ item }}",
|
|
"state": "stopped",
|
|
"enabled": "no",
|
|
},
|
|
WithPlugin: "items",
|
|
WithPluginVal: "{{ oldconfs.stdout_lines }}",
|
|
When: "(not oldconfs.failed) and (item not in wireguard_networks)",
|
|
},
|
|
&ansiblev2.Task{
|
|
Name: "Configure wireguard conf",
|
|
ModuleName: "template",
|
|
ModuleArgs: map[string]interface{}{
|
|
"src": "wgX.conf.j2", // wgX_conf_j2
|
|
"dest": "/etc/wireguard/{{ item }}.conf",
|
|
"mode": 0600,
|
|
},
|
|
WithPlugin: "items",
|
|
WithPluginVal: "{{ wireguard_networks }}",
|
|
Register: "configuration",
|
|
},
|
|
&ansiblev2.Task{
|
|
Name: "Enable wg-quick@xx service",
|
|
ModuleName: "service",
|
|
ModuleArgs: map[string]interface{}{
|
|
"name": "wg-quick@{{ item }}",
|
|
"enabled": "yes",
|
|
},
|
|
WithPlugin: "items",
|
|
WithPluginVal: "{{ wireguard_networks }}",
|
|
},
|
|
&ansiblev2.Task{
|
|
Name: "Restart wg-quick@xx service",
|
|
ModuleName: "service",
|
|
ModuleArgs: map[string]interface{}{
|
|
"name": "wg-quick@{{ item.1 }}",
|
|
"state": "restarted",
|
|
},
|
|
WithPlugin: "indexed_items",
|
|
WithPluginVal: "{{ wireguard_networks }}",
|
|
When: "configuration.results[item.0].changed",
|
|
},
|
|
)
|
|
play.Hosts = "all"
|
|
play.Name = "Configure wireguard networks"
|
|
return play
|
|
}
|
|
|
|
func (router *SRouter) playDeployRoutes() (*ansiblev2.Play, error) {
|
|
r, err := RouteManager.routeLinesRouter(router)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
tasks := []ansiblev2.ITask{}
|
|
i := 0
|
|
for ifname, lines := range r {
|
|
if len(lines) == 0 {
|
|
continue
|
|
}
|
|
iface, err := IfaceManager.getByRouterIfname(router, ifname)
|
|
if err != nil {
|
|
return nil, errors.WithMessagef(err, "get iface %s", ifname)
|
|
}
|
|
filename := "route-" + ifname
|
|
content := strings.Join(lines, "\n") + "\n"
|
|
registerVar := fmt.Sprintf("var%d", i)
|
|
i += 1
|
|
tasks = append(tasks, &ansiblev2.Task{
|
|
Name: "Put routes for " + ifname,
|
|
ModuleName: "copy",
|
|
ModuleArgs: map[string]interface{}{
|
|
"content": content,
|
|
"dest": "/etc/sysconfig/network-scripts/" + filename,
|
|
"owner": "root",
|
|
"group": "root",
|
|
"mode": "0644",
|
|
},
|
|
Register: registerVar,
|
|
})
|
|
if !iface.isTypeWireguard() {
|
|
tasks = append(tasks, &ansiblev2.ShellTask{
|
|
Name: fmt.Sprintf("Apply routes (Ifup/ifdown %s)", ifname),
|
|
Script: fmt.Sprintf("ifdown %s; ifup %s", ifname, ifname),
|
|
IgnoreErrors: true,
|
|
When: fmt.Sprintf("%s.changed", registerVar),
|
|
})
|
|
}
|
|
// apply by diff on changed
|
|
}
|
|
play := ansiblev2.NewPlay(tasks...)
|
|
play.Hosts = "all"
|
|
play.Name = "Configure routes"
|
|
return play, nil
|
|
}
|
|
|
|
func (router *SRouter) playDeployRules() (*ansiblev2.Play, error) {
|
|
d, err := RuleManager.firewalldDirectByRouter(router)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
directXML, err := xml.MarshalIndent(d, "", " ")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
play := ansiblev2.NewPlay(
|
|
&ansiblev2.Task{
|
|
Name: "Install firewalld",
|
|
ModuleName: "package",
|
|
ModuleArgs: map[string]interface{}{
|
|
"name": "firewalld",
|
|
"state": "present",
|
|
},
|
|
},
|
|
&ansiblev2.Task{
|
|
Name: "Enable firewalld",
|
|
ModuleName: "service",
|
|
ModuleArgs: map[string]interface{}{
|
|
"name": "firewalld",
|
|
"enabled": "yes",
|
|
},
|
|
},
|
|
&ansiblev2.Task{
|
|
Name: "Put firewalld direct.xml",
|
|
ModuleName: "copy",
|
|
ModuleArgs: map[string]interface{}{
|
|
"content": string(directXML),
|
|
"dest": "/etc/firewalld/direct.xml",
|
|
"owner": "root",
|
|
"group": "root",
|
|
"mode": "0644",
|
|
},
|
|
Register: "direct_xml",
|
|
},
|
|
&ansiblev2.Task{
|
|
Name: "Restart firewalld",
|
|
ModuleName: "service",
|
|
ModuleArgs: map[string]interface{}{
|
|
"name": "firewalld",
|
|
"state": "restarted",
|
|
},
|
|
When: "direct_xml.changed",
|
|
},
|
|
)
|
|
play.Hosts = "all"
|
|
play.Name = "Configure firewall rules"
|
|
return play, nil
|
|
}
|
|
|
|
func (router *SRouter) playEssential() *ansiblev2.Play {
|
|
play := ansiblev2.NewPlay(
|
|
&ansiblev2.Task{
|
|
Name: "Enable ip_forward",
|
|
ModuleName: "sysctl",
|
|
ModuleArgs: map[string]interface{}{
|
|
"name": "net.ipv4.ip_forward",
|
|
"value": "1",
|
|
"state": "present",
|
|
"reload": "yes",
|
|
},
|
|
},
|
|
)
|
|
play.Hosts = "all"
|
|
play.Name = "Perform essential steps"
|
|
return play
|
|
}
|