Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vsock: Add alternate http/https port in case 80/443 in use #3332

Merged
merged 1 commit into from
Sep 19, 2022

Conversation

praveenkumar
Copy link
Member

This patch try to solve user issue where port 80 or 443 already in
use and crc start fails by having alternate port 8080 and 8443.

Note: Now user have to add those ports to application routes to access
it. Like https://myapp.apps-crc.testing:8443 or http://myapp.apps-crc.testing:8080

$ ./crc start
[...]
WARN Port 80 is already in use. Going to use 8080

$ curl --unix-socket ~/.crc/crc-http.sock http:/unix/network/services/forwarder/all | jq .
[
  {
    "local": "127.0.0.1:2222",
    "remote": "192.168.127.2:22",
    "protocol": "tcp"
  },
  {
    "local": "127.0.0.1:6443",
    "remote": "192.168.127.2:6443",
    "protocol": "tcp"
  },
  {
    "local": ":443",
    "remote": "192.168.127.2:443",
    "protocol": "tcp"
  },
  {
    "local": ":8080",
    "remote": "192.168.127.2:80",
    "protocol": "tcp"
  }
]

Fixes: Issue #3331

func HTTPAndHTTPS() []types.ExposeRequest {
hPort, hsPort := httpPort, httpsPort
if isPortInUse(hPort) {
logging.Warnf("Port %s is already in use. Going to use %s", httpPort, alternateHTTPPort)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using port %s instead might sound nicer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the very last warning which is printed? Or is this going to be lost in the middle of the startup logs of crc?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going to use does not sound conclusive. Assigned %s instead, as use followed by using sounds repetitive.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the very last warning which is printed? Or is this going to be lost in the middle of the startup logs of crc?

@cfergeau It is not the last warning, this is something part of info messages (Since it is warning so should've the WARN and different color)

Copy link
Contributor

@cfergeau cfergeau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Now user have to add those ports to application routes to access
it. Like https://myapp.apps-crc.testing:8443 or http://myapp.apps-crc.testing:8080

This should be more than a note in the commit log, but part of the warning which is displayed to the user. This also needs to be mentioned in documentation.

}

func isPortInUse(port string) bool {
ln, err := net.Listen("tcp", ":"+port)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could use fmt.Sprintf for consistency with the code before it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fwiw, listening on port 80/443 is a privileged operation on some OS, I don't know if isPortInUse could fail because of this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fwiw, listening on port 80/443 is a privileged operation on some OS, I don't know if isPortInUse could fail because of this.

@cfergeau I checked with linux/mac running a python simple http server on port 80 and this is identified by this function.

func HTTPAndHTTPS() []types.ExposeRequest {
hPort, hsPort := httpPort, httpsPort
if isPortInUse(hPort) {
logging.Warnf("Port %s is already in use. Going to use %s", httpPort, alternateHTTPPort)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the very last warning which is printed? Or is this going to be lost in the middle of the startup logs of crc?

Protocol: "tcp",
Local: fmt.Sprintf(":%s", hPort),
Remote: net.JoinHostPort(virtualMachineIP, httpPort),
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd have a preference for not putting http/https together to avoid code duplication.

exposeRequest = append(exposeRequest, requestWithAlternatePort(httpPort, alternateHTTPPort)
exposeRequest = append(exposeRequest, requestWithAlternatePort(httpsPort, alternateHTTPSPort)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternate is not the right wording as that means that either can be assigned consecutively.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fallback would work.

@gbraad
Copy link
Contributor

gbraad commented Sep 6, 2022

WARN Port 80 is already in use. Going to use 8080

WARN Port 80 is already in use. Assigned 8080 as alternative.

internalSSHPort = "22"
localIP = "127.0.0.1"
httpPort = "80"
alternateHTTPPort = "8080"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most common use of alternate is 'every other'. better use alternative

Copy link
Contributor

@gbraad gbraad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wording

@praveenkumar
Copy link
Member Author

Note: Now user have to add those ports to application routes to access
it. Like https://myapp.apps-crc.testing:8443 or http://myapp.apps-crc.testing:8080

This should be more than a note in the commit log, but part of the warning which is displayed to the user. This also needs to be mentioned in documentation.

@cfergeau Now this warning propagated to start. Let me know if we want this change in separate commit (like now) or you want to squash the last 2 commits.

@anjannath
Copy link
Member

when a fallback port is chosen for HTTPS then the crc console command won't be giving the correct URL for the console, it'd be nice if crc console knew which port to use

something we can document or need to solve in a follow up pr

@gbraad
Copy link
Contributor

gbraad commented Sep 8, 2022

knew which port to use

would need to be stored as part of the machine config as state :-/

@anjannath
Copy link
Member

knew which port to use

would need to be stored as part of the machine config as state :-/

we can also get this information from the daemon, listing the exposed ports

@praveenkumar
Copy link
Member Author

knew which port to use

would need to be stored as part of the machine config as state :-/

we can also get this information from the daemon, listing the exposed ports

yes I was going to use this solution but #3331 (comment) need discussion so putting that to hold.

/hold

@praveenkumar
Copy link
Member Author

/unhold

pkg/crc/config/types.go Show resolved Hide resolved
pkg/crc/config/validations.go Show resolved Hide resolved
@@ -31,6 +31,10 @@ type StartConfig struct {

// Shared dirs
EnableSharedDirs bool

// Port to access openshift route
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ports to access OpenShift routes?

@@ -102,12 +102,12 @@ func vsockPorts(preset crcPreset.Preset) []types.ExposeRequest {
},
types.ExposeRequest{
Protocol: "tcp",
Local: fmt.Sprintf(":%s", httpsPort),
Local: fmt.Sprintf(":%s", strconv.FormatUint(uint64(ingressHTTPSPort), 10)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:%d should work?

pkg/crc/machine/vsock.go Outdated Show resolved Hide resolved
if userAssignedHTTPPort != httpPort {
fallbackPortWarning += fmt.Sprintf(fallbackPortWarningTmpl, userAssignedHTTPPort, "http", userAssignedHTTPPort)
}
return fallbackPortWarning
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really see the point of carrying this warning string all the way from pkg/crc/machine/vsock.go so that it can be displayed in cmd/crc/cmd/start.go. We could just check if ingress-http-port/ingress-https-port are set to their default values, and print the warning if not?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could just check if ingress-http-port/ingress-https-port are set to their default values, and print the warning if not?

@cfergeau where you want to check it, in cmd/start.go ? If I do that I can't have it at the end as what we discussed previously so current implementation seemed clean to me.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current implementation prints the message in cmd/start.go and manages to print it at the end, so I don't understand your objection?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current implementation prints the message in cmd/start.go and manages to print it at the end, so I don't understand your objection?

@cfergeau current implementation works because we carry this warning from pkg/crc/machine/vsock.go or you are saying we just should should check that in pkg/crc/machine/start.go and return from there?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If done in pkg/crc/machine/start.go, I'd prefer to see expose it as fallbackHTTPPortInUse bool; fallbackHTTPSPortInUse bool;, and convert this to a warning in cmd/start.go. It's probably fine to not even do that, and check the config in cmd/start.go? Or does it have downsides?

@@ -32,3 +32,13 @@ func RequiresCRCSetup(key string, _ interface{}) string {
return fmt.Sprintf("Changes to configuration property '%s' are only applied during 'crc setup'.\n"+
"Please run 'crc setup' for this configuration to take effect.", key)
}

func RequiresHTTPPortChangeWarning(key string, value interface{}) string {
return fmt.Sprintf("Changes to configuration property '%s' will break the openshift route.\n"+
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... will break OpenShift HTTP routes. In order to access OpenShift applications through HTTP URLs, the %d port must be manually specified, such as http://myapp.apps-crc.testing:%d

}

func RequiresHTTPSPortChangeWarning(key string, value interface{}) string {
return fmt.Sprintf("Changes to configuration property '%s' will break the openshift webconsole.\n"+
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need the same warning as in the HTTP case, plus something for the web console. After this change, the OpenShift console will be non-functional because of OpenShift limitations (dunno if it's possible to insert the URL of the web console in this message?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need the same warning as in the HTTP case, plus something for the web console. After this change, the OpenShift console will be non-functional because of OpenShift limitations

Sure, that we can do.

dunno if it's possible to insert the URL of the web console in this message?

Not at this moment because web console url is created from bundle metadata side.

@@ -107,6 +109,10 @@ func RegisterSettings(cfg *Config) {

cfg.AddSetting(KubeAdminPassword, "", ValidateString, SuccessfullyApplied,
"User defined kubeadmin password")
cfg.AddSetting(IngressHTTPPort, 80, ValidatePort, RequiresHTTPPortChangeWarning,
"Consent to use alternative http port in case 80 is in use (1024-65535, default: 80)")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consent to use? "Alternative HTTP port to use for OpenShift ingress/routes in case port 80 is already in use on the host" ? But this could be too long.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I can put it, too long shouldn't be issue if it make more clear message to user.

fallbackPortWarningTmpl := `
Note: Port %s is Assigned.
You have to add this port to the application route to access
it. like %s://myapp.apps-crc.testing:%s
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to acces it. like %s .. -> to access it, such as %s://myapp.apps-crc.testing:%s

cmd/crc/cmd/start.go Outdated Show resolved Hide resolved
fallbackPortWarningTmpl := `
Note: Port %d is Assigned.
You have to add this port to the application route to access
it, such as %s://myapp.apps-crc.testing:%d
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The config warning uses slightly different terminology:

Changes to configuration property '%s' will break OpenShift HTTPS routes.\n"+
		"In order to access OpenShift applications through HTTPS URLs "+
		"the %d port must be manually specified, such as https://myapp.apps-crc.testing:%d\n"

" OpenShift HTTPS routes" and "OpenShift applications through HTTPS URLs" is used rather than "the application route"

Maybe Port %d is used for OpenShift HTTP routes instead of the default. You have to add this port to HTTP URLs when accessing OpenShift application, such as ... ?

cfg.AddSetting(IngressHTTPPort, constants.OpenShiftIngressHTTPPort, ValidatePort, RequiresHTTPPortChangeWarning,
fmt.Sprintf("Alternative HTTP port to use for OpenShift ingress/routes in case port 80 is already in use on the host (1024-65535, default: %d)", constants.OpenShiftIngressHTTPPort))
cfg.AddSetting(IngressHTTPSPort, constants.OpenShiftIngressHTTPSPort, ValidatePort, RequiresHTTPSPortChangeWarning,
fmt.Sprintf("Alternative HTTPS port to use for OpenShift ingress/routes in case port 443 is already in use on the host (1024-65535, default: %d)", constants.OpenShiftIngressHTTPSPort))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The in case port xx is already in use on the host is no longer accurate, the defined port will always be used.

@@ -268,6 +276,9 @@ func writeOpenShiftTemplatedMessage(writer io.Writer, s *startResult) error {
if s.ClusterConfig.ClusterType == preset.OKD {
tmpl = fmt.Sprintf("%s\n\n%s", startTemplateForOpenshift, startTemplateForOKD)
}
if s.FallbackPortWarning != "" {
tmpl = fmt.Sprintf("%s\n%s", tmpl, fallbackPortWarning)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we get any benefits from having FallbackPortWarning in startResult rather than calling portFallbackWarning() here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is not part of result then you will not get it as part of crc start -ojson, in case some other app want to make use of this warning to show then it can be used.

$ crc start -o json
[...]
   "developerCredentials": {
      "username": "developer",
      "password": "developer"
    }
  },
  "fallbackPortWarning": "\nNote: Port 8080 is Assigned.\nYou have to add this port to the application route to access\nit, such as http://myapp.apps-crc.testing:8080\n"
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to expose this in json, this would look more useful than an arbitrary string:

[...]
   "developerCredentials": {
      "username": "developer",
      "password": "developer"
    }
  },
  "alternativeIngressPorts": {
      "http": "8080",
  }
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What we want to expose is debatable, warning can be useful if the app just need to popup or even show in the terminal. Also this is the same warning what crc start cmd shows. If we just put alternativeIngressPorts then user of it need to put own interpretation/warning around it.

Copy link
Contributor

@cfergeau cfergeau Sep 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion, a preformatted string is almost never the right thing to have in an API, be it a json struct, a function return value, ... As soon as you need something different from the hardcoded string, you have to add awkward parsing code to get back the original data, and rebuild what you need from it.
One way forward is to not add anything to the json output for now, and to add 'something' when we have clear requirements for it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cfergeau Ack, I remove the warn string from json output now.

func portFallbackWarning() string {
var fallbackPortWarning string
fallbackPortWarningTmpl := `
Note: Port %d is Assigned.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the method called 'Warning' but the string is Note:? :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cfergeau I put the Warning instead Note.

@praveenkumar praveenkumar added the has-to-be-in-release This PR need to go in coming release. label Sep 16, 2022
This patch try to solve user issue where port 80 or 443 already in
use and `crc start` fails by providing user an option as part of `crc
config set` to have different http/https port.

This patch also add callback function and startup warning in case port
setting is choose by user.
```
$ crc config set ingress-http-port 8080
Changes to configuration property 'ingress-http-port' will break the openshift route.
User need to add 8080 port to application route to access it. like http://myapp.apps-crc.testing:8080

$ crc start
[...]
Use the 'oc' command line interface:
  $ eval $(crc oc-env)
  $ oc login -u developer https://api.crc.testing:6443

Warning: Port 80 is already in use. Assigned port 8080 instead.
You have to add thise port to the application route to access
it. like http://myapp.apps-crc.testing:8080

$ curl --unix-socket ~/.crc/crc-http.sock http:/unix/network/services/forwarder/all | jq .
[
  {
    "local": "127.0.0.1:2222",
    "remote": "192.168.127.2:22",
    "protocol": "tcp"
  },
  {
    "local": "127.0.0.1:6443",
    "remote": "192.168.127.2:6443",
    "protocol": "tcp"
  },
  {
    "local": ":443",
    "remote": "192.168.127.2:443",
    "protocol": "tcp"
  },
  {
    "local": ":8080",
    "remote": "192.168.127.2:80",
    "protocol": "tcp"
  }
]
```
@openshift-ci
Copy link

openshift-ci bot commented Sep 16, 2022

@praveenkumar: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-crc 04ce01c link true /test e2e-crc

Full PR test history. Your PR dashboard.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

fallbackPortWarningTmpl := `
Warning: Port %d is used for OpenShift %s routes instead of the default
You have to add this port to %s URLs when accessing OpenShift application,
such as %s://myapp.apps-crc.testing:%d
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning that the console will be non-functional would be useful here as well. Especially as one message just before the warning is

The server is accessible via web console at:
  {{ .ClusterConfig.WebConsoleURL }}

A follow-up would be to remove this message when the https is overridden.

Copy link
Contributor

@gbraad gbraad Sep 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Address as a follow-up: #3350

@openshift-ci
Copy link

openshift-ci bot commented Sep 19, 2022

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: cfergeau

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved has-to-be-in-release This PR need to go in coming release. lgtm
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants