@@ -99,6 +99,10 @@ type DockerClient struct {
9999 // Guard against concurrent async refreshes
100100 refreshMu sync.Mutex
101101 refreshing map [string ]bool
102+
103+ // Cached SSH context check
104+ isSSHOnce sync.Once
105+ isSSH bool
102106}
103107
104108func NewDockerClient (contextName string , apiTimeout time.Duration , defaultContext string ) (* DockerClient , error ) {
@@ -638,6 +642,22 @@ func (d *DockerClient) CreateContext(name, description, host string) error {
638642 return nil
639643}
640644
645+ func (d * DockerClient ) UpdateContext (name , description , host string ) error {
646+ args := []string {"context" , "update" , name }
647+ if description != "" {
648+ args = append (args , "--description" , description )
649+ }
650+ if host != "" {
651+ args = append (args , "--docker" , fmt .Sprintf ("host=%s" , host ))
652+ }
653+ cmd := exec .Command ("docker" , args ... )
654+ output , err := cmd .CombinedOutput ()
655+ if err != nil {
656+ return fmt .Errorf ("error updating context: %v, output: %s" , err , string (output ))
657+ }
658+ return nil
659+ }
660+
641661func (d * DockerClient ) ListPlugins () ([]PluginInfo , error ) {
642662 cmd := exec .Command ("docker" , "plugin" , "ls" , "--format" , "{{json .}}" )
643663 output , err := cmd .CombinedOutput ()
@@ -956,6 +976,99 @@ func (d *DockerClient) ListVolumesForContainer(id string) ([]common.Resource, er
956976 return result , nil
957977}
958978
979+ func (d * DockerClient ) IsSSHContext () bool {
980+ d .isSSHOnce .Do (func () {
981+ ctxList , err := ListContexts ()
982+ if err != nil {
983+ return
984+ }
985+ for _ , c := range ctxList {
986+ if c .Name == d .ContextName {
987+ d .isSSH = strings .HasPrefix (c .DockerEndpoint , "ssh://" )
988+ return
989+ }
990+ }
991+ })
992+ return d .isSSH
993+ }
994+
995+ func (d * DockerClient ) GetSSHHost () string {
996+ ctxList , err := ListContexts ()
997+ if err != nil {
998+ return ""
999+ }
1000+ for _ , c := range ctxList {
1001+ if c .Name == d .ContextName {
1002+ host := strings .TrimPrefix (c .DockerEndpoint , "ssh://" )
1003+ return host
1004+ }
1005+ }
1006+ return ""
1007+ }
1008+
1009+ type ContainerPortInfo struct {
1010+ ContainerPort uint16
1011+ HostPort uint16
1012+ Protocol string
1013+ IP string
1014+ }
1015+
1016+ func (d * DockerClient ) GetContainerIP (id string ) (string , error ) {
1017+ cj , err := d .Cli .ContainerInspect (d .Ctx , id )
1018+ if err != nil {
1019+ return "" , err
1020+ }
1021+ if cj .NetworkSettings == nil {
1022+ return "" , fmt .Errorf ("no network settings for container %s" , id )
1023+ }
1024+ for _ , n := range cj .NetworkSettings .Networks {
1025+ if n .IPAddress != "" {
1026+ return n .IPAddress , nil
1027+ }
1028+ }
1029+ return "" , fmt .Errorf ("no IP found for container %s" , id )
1030+ }
1031+
1032+ func (d * DockerClient ) GetContainerPorts (id string ) ([]ContainerPortInfo , error ) {
1033+ cj , err := d .Cli .ContainerInspect (d .Ctx , id )
1034+ if err != nil {
1035+ return nil , err
1036+ }
1037+
1038+ var ports []ContainerPortInfo
1039+
1040+ if cj .NetworkSettings != nil {
1041+ for port , bindings := range cj .NetworkSettings .Ports {
1042+ cp := ContainerPortInfo {
1043+ ContainerPort : uint16 (port .Int ()),
1044+ Protocol : port .Proto (),
1045+ }
1046+ if len (bindings ) > 0 {
1047+ cp .HostPort = parsePort (bindings [0 ].HostPort )
1048+ cp .IP = bindings [0 ].HostIP
1049+ }
1050+ ports = append (ports , cp )
1051+ }
1052+ }
1053+
1054+ if len (ports ) == 0 && cj .Config != nil {
1055+ for port := range cj .Config .ExposedPorts {
1056+ ports = append (ports , ContainerPortInfo {
1057+ ContainerPort : uint16 (port .Int ()),
1058+ Protocol : port .Proto (),
1059+ })
1060+ }
1061+ }
1062+
1063+ return ports , nil
1064+ }
1065+
1066+ func parsePort (s string ) uint16 {
1067+ var p int
1068+ fmt .Sscanf (s , "%d" , & p )
1069+ return uint16 (p )
1070+ }
1071+
9591072func (d * DockerClient ) ListNetworksForContainer (id string ) ([]common.Resource , error ) {
9601073 // 1. Get container network info (cache first, API fallback)
9611074 d .cacheMu .RLock ()
0 commit comments