Skip to content

Latest commit

 

History

History
120 lines (95 loc) · 3.55 KB

File metadata and controls

120 lines (95 loc) · 3.55 KB

Сохранение конфигурации коммутатора

Данная операция необходима для сохранения текущей конфигурации данного коммутатора

Обзор операции

Данная операция реализуется следующим RPC:

// Описание сервиса для мониторинга доступности и управления конфигурациями коммутаторов
service NetworkManager {
  // процедура для сохранения настроек коммутатора
  rpc CreateConfig(CreateNetworkConfigRequest) returns (CreateNetworkConfigResponse);
}

message CreateNetworkConfigRequest {
  DeviceContent device = 1;
}

message CreateNetworkConfigResponse {
  OperationResult result = 1;
}

С полной структурой данных вы можете ознакомиться в прото-файлах.

Пример реализации

Реализация операции будет производиться на Microtik RouterOS.

Дополняем уже имеющийся шаблон реализацией RPC CreateConfig.

Во входящем запросе мы получаем данные подключения и адрес для подключения к ОС коммутатора. Для начала нам нужно извлечь их. Создадим удобную структуру для их хранения:

type sshConnInfo struct {
	addr  string
	login string
	pass  string
	port  int32
}

Теперь создадим функцию для извлечения этих данных подключения:

func extractSSHConnInfo(connectors []*pb.DeviceConnector) (sshConnInfo, error) {
	for _, conn := range connectors {
		for _, creds := range conn.Credentials {
			if creds.Protocol == pb.ConnectorProtocol_CONNECTOR_PROTOCOL_SSH {
				res := sshConnInfo{
					addr:  conn.Address,
					login: creds.Login,
					pass:  creds.Password,
					port:  creds.Port,
				}
				return res, nil
			}
		}
	}
	return sshConnInfo{}, fmt.Errorf("ssh credentials were not found")
}

Теперь мы можем использовать эту функцию для извлечения данных подключения и сознания клиента:

info, err := extractSSHConnInfo(req.Device.Connectors)
if err != nil {
	return nil, err
}

cfg := &ssh.ClientConfig{
	User: info.login,
	HostKeyCallback: ssh.HostKeyCallback(
		func(hostname string, remote net.Addr, key ssh.PublicKey) error {
			return nil
		}),
	Auth: []ssh.AuthMethod{
		ssh.Password(info.pass),
	},
}

conn, err := ssh.Dial("tcp", info.addr, cfg)
if err != nil {
	return nil, err
}

session, err := conn.NewSession()
if err != nil {
	return nil, err
}
defer session.Close()

Далее мы соединяем stdout ssh-сессии с байтовым буфером, и запускаем удаленную команду:

var b bytes.Buffer
session.Stdout = &b

if err := session.Run(createConfigCmd); err != nil {
	return nil, err
}

В завершении, скомпонуем ответ для RPC, используя полученные данные:

res := pb.CreateNetworkConfigResponse{
	Result: &pb.OperationResult{
		DeviceId: req.Device.DeviceId,
		State:    pb.OperationState_OPERATION_STATE_SUCCESS,
		Output:   b.String(),
	},
}

return &res, nil