Files
oci-portal/internal/oci/consoleconnection.go
T

112 lines
4.2 KiB
Go

package oci
import (
"context"
"fmt"
"time"
"github.com/oracle/oci-go-sdk/v65/core"
)
// ConsoleConnection 是实例控制台连接。VNC 连接串在本地建立 SSH 隧道后,
// 用 VNC 客户端连 localhost:5900 即可(串口控制台直接执行 ConnectionString)。
type ConsoleConnection struct {
ID string `json:"id"`
InstanceID string `json:"instanceId"`
LifecycleState string `json:"lifecycleState"`
ConnectionString string `json:"connectionString"` // 串口控制台 SSH 命令
VncConnectionString string `json:"vncConnectionString"` // VNC over SSH 隧道命令
}
// CreateConsoleConnection 实现 Client:为实例创建控制台连接并等待就绪,
// 返回包含 VNC/串口连接串的对象;等待超时返回当前状态(可稍后再查列表)。
func (c *RealClient) CreateConsoleConnection(ctx context.Context, cred Credentials, region, instanceID, sshPublicKey string) (ConsoleConnection, error) {
cc, err := c.computeClient(cred, region)
if err != nil {
return ConsoleConnection{}, err
}
resp, err := cc.CreateInstanceConsoleConnection(ctx, core.CreateInstanceConsoleConnectionRequest{
CreateInstanceConsoleConnectionDetails: core.CreateInstanceConsoleConnectionDetails{
InstanceId: &instanceID,
PublicKey: &sshPublicKey,
},
})
if err != nil {
return ConsoleConnection{}, fmt.Errorf("create console connection: %w", err)
}
return c.waitConsoleConnectionActive(ctx, cc, deref(resp.Id))
}
// waitConsoleConnectionActive 轮询等待控制台连接 ACTIVE,最长约 60 秒。
func (c *RealClient) waitConsoleConnectionActive(ctx context.Context, cc core.ComputeClient, connectionID string) (ConsoleConnection, error) {
var last ConsoleConnection
for i := 0; i < 30; i++ {
resp, err := cc.GetInstanceConsoleConnection(ctx, core.GetInstanceConsoleConnectionRequest{
InstanceConsoleConnectionId: &connectionID,
})
if err != nil {
return last, fmt.Errorf("poll console connection: %w", err)
}
last = toConsoleConnection(resp.InstanceConsoleConnection)
if last.LifecycleState == string(core.InstanceConsoleConnectionLifecycleStateActive) {
return last, nil
}
select {
case <-ctx.Done():
return last, fmt.Errorf("poll console connection: %w", ctx.Err())
case <-time.After(2 * time.Second):
}
}
return last, nil
}
// ListConsoleConnections 实现 Client:列出实例的控制台连接。
func (c *RealClient) ListConsoleConnections(ctx context.Context, cred Credentials, region, instanceID string) ([]ConsoleConnection, error) {
cc, err := c.computeClient(cred, region)
if err != nil {
return nil, err
}
// 控制台连接记录在实例所在 compartment,先取实例定位,传租户根会漏查
instResp, err := cc.GetInstance(ctx, core.GetInstanceRequest{InstanceId: &instanceID})
if err != nil {
return nil, fmt.Errorf("get instance %s: %w", instanceID, err)
}
resp, err := cc.ListInstanceConsoleConnections(ctx, core.ListInstanceConsoleConnectionsRequest{
CompartmentId: hostCompartment(cred, deref(instResp.CompartmentId)),
InstanceId: &instanceID,
})
if err != nil {
return nil, fmt.Errorf("list console connections: %w", err)
}
connections := make([]ConsoleConnection, 0, len(resp.Items))
for _, item := range resp.Items {
connections = append(connections, toConsoleConnection(item))
}
return connections, nil
}
// DeleteConsoleConnection 实现 Client:删除控制台连接。
func (c *RealClient) DeleteConsoleConnection(ctx context.Context, cred Credentials, region, connectionID string) error {
cc, err := c.computeClient(cred, region)
if err != nil {
return err
}
_, err = cc.DeleteInstanceConsoleConnection(ctx, core.DeleteInstanceConsoleConnectionRequest{
InstanceConsoleConnectionId: &connectionID,
})
if err != nil {
return fmt.Errorf("delete console connection %s: %w", connectionID, err)
}
return nil
}
func toConsoleConnection(conn core.InstanceConsoleConnection) ConsoleConnection {
return ConsoleConnection{
ID: deref(conn.Id),
InstanceID: deref(conn.InstanceId),
LifecycleState: string(conn.LifecycleState),
ConnectionString: deref(conn.ConnectionString),
VncConnectionString: deref(conn.VncConnectionString),
}
}