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), } }