Golang 读取文本中的信息 SSH 登录设备

背景

在go中为多台设备配置时可以定义一个数组解决,如果设备到几十或者上百台时我们改怎么办了?我们可以将设备信息和命令配置在文本中,下面跟笔者一起看一下 go 是如何通过文本中的信息批量配置设备的吧。

系统环境

  • win 11
  • go 1.18.1

配置脚本

创建go文件

笔者创建了一个名为 login_sw 的文件夹,在文件下创建一个名为 login_sw.go 的文件,将下列代码复制到文件中并保存,效果如图所示:
Pasted image 20221029222133

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"log"
	"os"
	"time"

	"golang.org/x/crypto/ssh"
)

func loginHosts(host_file string) ([]string, error) {
	var hostList []string
	// 获取当前路径
	path_file, _ := os.Getwd()
	// Go读取文件时需要使用绝对路径
	hf, err := os.Open(path_file + host_file)
	// 判断结果是否唯空
	if err != nil {
		return nil, err
	}
	// 读取文本中的信息
	scanner := bufio.NewScanner(hf)
	// 将文本中的内容切片,每行切成一个
	scanner.Split(bufio.ScanLines)
	// 遍历切片内容,将切片后的信息写入 hostList 数组中
	for scanner.Scan() {
		hostList = append(hostList, scanner.Text())
	}
	// 打印获取到的IP地址
	hf.Close()
	fmt.Printf("获取的设备ip是: %v \n\n", hostList)
	return hostList, nil
}

func readCommand(cmd_file string) ([]string, error) {
	var cmdList []string
	// 获取当前路径
	path_file, _ := os.Getwd()
	// Go读取文件时需要使用绝对路径
	hf, err := os.Open(path_file + cmd_file)
	// 判断结果是否唯空
	if err != nil {
		return nil, err
	}
	// 读取文本中的信息
	scanner := bufio.NewScanner(hf)
	// 将文本中的内容切片,每行切成一个
	scanner.Split(bufio.ScanLines)
	// 遍历切片内容,将切片后的信息写入 cmdList 数组中
	for scanner.Scan() {
		cmdList = append(cmdList, scanner.Text())
	}
	// 打印获取到的命令
	hf.Close()
	fmt.Printf("获取的命令是: %v \n\n", cmdList)
	return cmdList, nil
}

func connect_device(device_ip string, command []string) (string, error) {
	var b bytes.Buffer
	user := "admin"
	pass := "qazxsw@123"
	targethost := device_ip + ":22"
	config := &ssh.ClientConfig{
		User: user,
		Auth: []ssh.AuthMethod{
			ssh.Password(pass),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}
	fmt.Printf("开始登录设备,设备IP是: %s \n", device_ip)
	conn, err := ssh.Dial("tcp", targethost, config)

	//用于故障排查
	// time.Sleep(1 * time.Second)
	//fmt.Println(conn)

	if err != nil {
		return (device_ip + " Failed to dial"), err
	}
	sess, err := conn.NewSession()

	// 延迟关闭连接,函数运行完成后再关闭
	defer conn.Close()
	if err != nil {
		return (device_ip + " Failed to create session"), err
	}
	stdin, err := sess.StdinPipe()
	if err != nil {
		return (device_ip + " Failed to create standard input"), err
	}
	// 用于存储设备回显信息
	sess.Stdout = &b
	// 异常信息直接打印出来
	sess.Stderr = os.Stderr

	// 向设备推送命令
	sess.Shell()
	for _, line := range command {
		fmt.Fprintf(stdin, "%s\n", line)
	}
	fmt.Fprintf(stdin, "quit\n")
	// 等待会话完成
	sess.Wait()
	// 关闭会话
	sess.Close()
	// 返回显信息
	return b.String(), nil
}

func main() {
	start_t := time.Now()
	// 获取文本中的命令信息
	commandList, err := readCommand("/cmd.cfg")
	if err != nil {
		// log.Fatal 遇到异常后直接退出脚本并打印错误信息
		log.Fatal("read command file err info is : ", err)
	}

	// 获取文本中的设备地址
	hostList, err := loginHosts("/host_file001.txt")
	if err != nil {
		// log.Fatal 遇到异常后直接退出脚本并打印错误信息
		log.Fatal("read host file err info is : ", err)
	}

	for _, host := range hostList {
		// 连接设备发送命令
		result, err := connect_device(host, commandList)
		if err != nil {
			fmt.Printf("错误信息是:%s %s \n\n", result, err)
		}
	}

	fmt.Printf("\n脚本运行时长是:%s", time.Since(start_t))
	// fmt.Println(time.Now().Sub(start_t)) 打印时长的第二种方法
}

编译环境

  • 通过终端将目录切换至脚本文件下
  • 执行下列代码
go mod init login_sw  // 使用`go mod init hello`初始化生成 go.mod 文件
go mod tidy        // 添加需要用到但go.mod中查不到的模块
go mod vendor      // 将新增的依赖包自动写入当前项目的 vendor 目录,下载依赖

Pasted image 20221029222445

创建设备IP文本

笔者使用文件名字为 host_file001.txt,文本中新增了两台设备。
注意:改变了文件名请一并更改脚本中的文件名
Pasted image 20221029222855

创建设备配置文本

笔者使用文件名字为 cmd.cfg,文本中新增两条查询命令。
注意:改变了文件名请一并更改脚本中的文件名
Pasted image 20221029223152

关于打印模块的小细节

Println  使用默认格式说明符格式化字符串,在字符串后添加新行
Print    使用默认格式说明符打印字符串格式,但不在字符串之后添加新行
Printf   使用自定义说明符格式化字符串。它也不会添加新行

有兴趣的可以前往官问查阅更多细节 fmt package - fmt - Go Packages

运行脚本

go run .\login_sw.go
结果如下图所示:
Pasted image 20221029233206

异常处理

如果出现找不到目录错误信息,由于 os.Getwd() 方法掉用的是运行 go run 命令的路径。
Pasted image 20221031141400

设备连接失败信息
Pasted image 20221031142310

基础入门

一些开源的中文书籍 Books · golang/go Wiki · GitHub
官方文档 Documentation - The Go Programming Language

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值