func (p *provider) GetAPIServerEndpoint(cluster string) (string, error) {
	// locate the node that hosts this
	allNodes, err := p.ListNodes(cluster)
	if err != nil {
		return "", errors.Wrap(err, "failed to list nodes")
	}
	n, err := nodeutils.APIServerEndpointNode(allNodes)
	if err != nil {
		return "", errors.Wrap(err, "failed to get api server endpoint")
	}

	// TODO: get rid of this once podman settles on how to get the port mapping using podman inspect
	// This is only used to get the Kubeconfig server field
	v, err := getPodmanVersion()
	if err != nil {
		return "", errors.Wrap(err, "failed to check podman version")
	}
	// podman inspect was broken between 2.2.0 and 3.0.0
	// https://github.com/containers/podman/issues/8444
	if v.AtLeast(version.MustParseSemantic("2.2.0")) &&
		v.LessThan(version.MustParseSemantic("3.0.0")) {
		p.logger.Warnf("WARNING: podman version %s not fully supported, please use versions 3.0.0+")

		cmd := exec.Command(
			"podman", "inspect",
			"--format",
			"{{range .NetworkSettings.Ports }}{{range .}}{{.HostIP}}/{{.HostPort}}{{end}}{{end}}",
			n.String(),
		)

		lines, err := exec.OutputLines(cmd)
		if err != nil {
			return "", errors.Wrap(err, "failed to get api server port")
		}
		if len(lines) != 1 {
			return "", errors.Errorf("network details should only be one line, got %d lines", len(lines))
		}
		// output is in the format IP/Port
		parts := strings.Split(strings.TrimSpace(lines[0]), "/")
		if len(parts) != 2 {
			return "", errors.Errorf("network details should be in the format IP/Port, received: %s", parts)
		}
		host := parts[0]
		port, err := strconv.Atoi(parts[1])
		if err != nil {
			return "", errors.Errorf("network port not an integer: %v", err)
		}

		return net.JoinHostPort(host, strconv.Itoa(port)), nil
	}

	cmd := exec.Command(
		"podman", "inspect",
		"--format",
		"{{ json .NetworkSettings.Ports }}",
		n.String(),
	)
	lines, err := exec.OutputLines(cmd)
	if err != nil {
		return "", errors.Wrap(err, "failed to get api server port")
	}
	if len(lines) != 1 {
		return "", errors.Errorf("network details should only be one line, got %d lines", len(lines))
	}

	// portMapping19 maps to the standard CNI portmapping capability used in podman 1.9
	// see: https://github.com/containernetworking/cni/blob/spec-v0.4.0/CONVENTIONS.md
	type portMapping19 struct {
		HostPort      int32  `json:"hostPort"`
		ContainerPort int32  `json:"containerPort"`
		Protocol      string `json:"protocol"`
		HostIP        string `json:"hostIP"`
	}
	// portMapping20 maps to the podman 2.0 portmap type
	// see: https://github.com/containers/podman/blob/05988fc74fc25f2ad2256d6e011dfb7ad0b9a4eb/libpod/define/container_inspect.go#L134-L143
	type portMapping20 struct {
		HostPort string `json:"HostPort"`
		HostIP   string `json:"HostIp"`
	}

	portMappings20 := make(map[string][]portMapping20)
	if err := json.Unmarshal([]byte(lines[0]), &portMappings20); err == nil {
		for k, v := range portMappings20 {
			protocol := "tcp"
			parts := strings.Split(k, "/")
			if len(parts) == 2 {
				protocol = strings.ToLower(parts[1])
			}
			containerPort, err := strconv.Atoi(parts[0])
			if err != nil {
				return "", err
			}
			for _, pm := range v {
				if containerPort == common.APIServerInternalPort && protocol == "tcp" {
					return net.JoinHostPort(pm.HostIP, pm.HostPort), nil
				}
			}
		}
	}

	var portMappings19 []portMapping19
	if err := json.Unmarshal([]byte(lines[0]), &portMappings19); err != nil {
		return "", errors.Errorf("invalid network details: %v", err)
	}
	for _, pm := range portMappings19 {
		if pm.ContainerPort == common.APIServerInternalPort && pm.Protocol == "tcp" {
			return net.JoinHostPort(pm.HostIP, strconv.Itoa(int(pm.HostPort))), nil
		}
	}

	return "", errors.Errorf("failed to get api server port")
}
// GetAPIServerEndpoint is part of the providers.Provider interface
GetAPIServerEndpoint is part of the providers.Provider interface
// GetAPIServerEndpoint is part of the providers . Provider interface
func (p *provider) GetAPIServerEndpoint(cluster string) (string, error) {
	allNodes, err := p.ListNodes(cluster)
	if err != nil {
		return "", errors.Wrap(err, "failed to list nodes")
	}
	n, err := nodeutils.APIServerEndpointNode(allNodes)
	if err != nil {
		return "", errors.Wrap(err, "failed to get api server endpoint")
	}
	v, err := getPodmanVersion()
	if err != nil {
		return "", errors.Wrap(err, "failed to check podman version")
	}
	if v.AtLeast(version.MustParseSemantic("2.2.0")) &&
		v.LessThan(version.MustParseSemantic("3.0.0")) {
		p.logger.Warnf("WARNING: podman version %s not fully supported, please use versions 3.0.0+")
		cmd := exec.Command(
			"podman", "inspect",
			"--format",
			"{{range .NetworkSettings.Ports }}{{range .}}{{.HostIP}}/{{.HostPort}}{{end}}{{end}}",
			n.String(),
		)
		lines, err := exec.OutputLines(cmd)
		if err != nil {
			return "", errors.Wrap(err, "failed to get api server port")
		}
		if len(lines) != 1 {
			return "", errors.Errorf("network details should only be one line, got %d lines", len(lines))
		}
		parts := strings.Split(strings.TrimSpace(lines[0]), "/")
		if len(parts) != 2 {
			return "", errors.Errorf("network details should be in the format IP/Port, received: %s", parts)
		}
		host := parts[0]
		port, err := strconv.Atoi(parts[1])
		if err != nil {
			return "", errors.Errorf("network port not an integer: %v", err)
		}
		return net.JoinHostPort(host, strconv.Itoa(port)), nil
	}
	cmd := exec.Command(
		"podman", "inspect",
		"--format",
		"{{ json .NetworkSettings.Ports }}",
		n.String(),
	)
	lines, err := exec.OutputLines(cmd)
	if err != nil {
		return "", errors.Wrap(err, "failed to get api server port")
	}
	if len(lines) != 1 {
		return "", errors.Errorf("network details should only be one line, got %d lines", len(lines))
	}
	type portMapping19 struct {
		HostPort      int32  `json:"hostPort"`
		ContainerPort int32  `json:"containerPort"`
		Protocol      string `json:"protocol"`
		HostIP        string `json:"hostIP"`
	}
	type portMapping20 struct {
		HostPort string `json:"HostPort"`
		HostIP   string `json:"HostIp"`
	}
	portMappings20 := make(map[string][]portMapping20)
	if err := json.Unmarshal([]byte(lines[0]), &portMappings20); err == nil {
		for k, v := range portMappings20 {
			protocol := "tcp"
			parts := strings.Split(k, "/")
			if len(parts) == 2 {
				protocol = strings.ToLower(parts[1])
			}
			containerPort, err := strconv.Atoi(parts[0])
			if err != nil {
				return "", err
			}
			for _, pm := range v {
				if containerPort == common.APIServerInternalPort && protocol == "tcp" {
					return net.JoinHostPort(pm.HostIP, pm.HostPort), nil
				}
			}
		}
	}
	var portMappings19 []portMapping19
	if err := json.Unmarshal([]byte(lines[0]), &portMappings19); err != nil {
		return "", errors.Errorf("invalid network details: %v", err)
	}
	for _, pm := range portMappings19 {
		if pm.ContainerPort == common.APIServerInternalPort && pm.Protocol == "tcp" {
			return net.JoinHostPort(pm.HostIP, strconv.Itoa(int(pm.HostPort))), nil
		}
	}
	return "", errors.Errorf("failed to get api server port")
}
func ( p * provider ) GetAPIServerEndpoint ( cluster string ) ( string , error ) { allNodes , err := p . ListNodes ( cluster ) if err != nil { return " " , errors . Wrap ( err , " " ) } n , err := nodeutils . APIServerEndpointNode ( allNodes ) if err != nil { return " " , errors . Wrap ( err , " " ) } v , err := getPodmanVersion ( ) if err != nil { return " " , errors . Wrap ( err , " " ) } if v . AtLeast ( version . MustParseSemantic ( " " ) ) && v . LessThan ( version . MustParseSemantic ( " " ) ) { p . logger . Warnf ( " " ) cmd := exec . Command ( " " , " " , " " , " " , n . String ( ) , ) lines , err := exec . OutputLines ( cmd ) if err != nil { return " " , errors . Wrap ( err , " " ) } if len ( lines ) != 1 { return " " , errors . Errorf ( " " , len ( lines ) ) } parts := strings . Split ( strings . TrimSpace ( lines [ 0 ] ) , " " ) if len ( parts ) != 2 { return " " , errors . Errorf ( " " , parts ) } host := parts [ 0 ] port , err := strconv . Atoi ( parts [ 1 ] ) if err != nil { return " " , errors . Errorf ( " " , err ) } return net . JoinHostPort ( host , strconv . Itoa ( port ) ) , nil } cmd := exec . Command ( " " , " " , " " , " " , n . String ( ) , ) lines , err := exec . OutputLines ( cmd ) if err != nil { return " " , errors . Wrap ( err , " " ) } if len ( lines ) != 1 { return " " , errors . Errorf ( " " , len ( lines ) ) } type portMapping19 struct { HostPort int32 `json:"hostPort"` ContainerPort int32 `json:"containerPort"` Protocol string `json:"protocol"` HostIP string `json:"hostIP"` } type portMapping20 struct { HostPort string `json:"HostPort"` HostIP string `json:"HostIp"` } portMappings20 := make ( map [ string ] [ ] portMapping20 ) if err := json . Unmarshal ( [ ] byte ( lines [ 0 ] ) , & portMappings20 ) ; err == nil { for k , v := range portMappings20 { protocol := " " parts := strings . Split ( k , " " ) if len ( parts ) == 2 { protocol = strings . ToLower ( parts [ 1 ] ) } containerPort , err := strconv . Atoi ( parts [ 0 ] ) if err != nil { return " " , err } for _ , pm := range v { if containerPort == common . APIServerInternalPort && protocol == " " { return net . JoinHostPort ( pm . HostIP , pm . HostPort ) , nil } } } } var portMappings19 [ ] portMapping19 if err := json . Unmarshal ( [ ] byte ( lines [ 0 ] ) , & portMappings19 ) ; err != nil { return " " , errors . Errorf ( " " , err ) } for _ , pm := range portMappings19 { if pm . ContainerPort == common . APIServerInternalPort && pm . Protocol == " " { return net . JoinHostPort ( pm . HostIP , strconv . Itoa ( int ( pm . HostPort ) ) ) , nil } } return " " , errors . Errorf ( " " ) }
GetAPIServerEndpoint is part of the providers.Provider interface
GetAPIServerEndpoint is part of the providers . Provider interface
// locate the node that hosts this // TODO: get rid of this once podman settles on how to get the port mapping using podman inspect // This is only used to get the Kubeconfig server field // podman inspect was broken between 2.2.0 and 3.0.0 // https://github.com/containers/podman/issues/8444 // output is in the format IP/Port // portMapping19 maps to the standard CNI portmapping capability used in podman 1.9 // see: https://github.com/containernetworking/cni/blob/spec-v0.4.0/CONVENTIONS.md // portMapping20 maps to the podman 2.0 portmap type // see: https://github.com/containers/podman/blob/05988fc74fc25f2ad2256d6e011dfb7ad0b9a4eb/libpod/define/container_inspect.go#L134-L143