package io.cattle.platform.core.util;
import io.cattle.platform.core.constants.PortConstants;
import io.cattle.platform.core.model.Port;
import io.cattle.platform.object.util.DataAccessor;
import io.github.ibuildthecloud.gdapi.exception.ClientVisibleException;
import io.github.ibuildthecloud.gdapi.util.ResponseCodes;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
public class PortSpec {
public static final String WRONG_FORMAT = "PortWrongFormat";
public static final String INVALID_PUBLIC_PORT = "PortInvalidPublicPort";
public static final String INVALID_PRIVATE_PORT = "PortInvalidPrivatePort";
public static final String INVALID_PROTOCOL = "PortInvalidProtocol";
private static final Pattern PATTERN = Pattern.compile("(([0-9]+):)?([0-9]+)(/(.*))?");
private static final List<String> PROTOCOLS = Arrays.asList("tcp", "udp");
int privatePort;
String ipAddress;
Integer publicPort;
String protocol;
public PortSpec() {
}
public PortSpec(Port port) {
this.ipAddress = DataAccessor.fieldString(port, PortConstants.FIELD_BIND_ADDR);
this.publicPort = port.getPublicPort();
this.privatePort = port.getPrivatePort();
this.protocol = port.getProtocol();
}
public PortSpec(String spec) {
// format: ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort | containerPort
// Check for an IP address
String[] parts = spec.split("\\]");
String ipAddr = null;
if (parts.length == 2) {
// IPv6, right?
if (!parts[0].startsWith("[")) {
throw new ClientVisibleException(ResponseCodes.UNPROCESSABLE_ENTITY, WRONG_FORMAT);
}
ipAddr = parts[0].replace("[", "");
spec = StringUtils.removeStart(parts[1], ":");
} else if (StringUtils.countMatches(spec, ":") == 2) {
parts = spec.split("\\:", 2);
ipAddr = parts[0];
spec = StringUtils.removeStart(parts[1], ":");
}
Matcher m = PATTERN.matcher(spec);
if (!m.matches()) {
throw new ClientVisibleException(ResponseCodes.UNPROCESSABLE_ENTITY, WRONG_FORMAT);
}
int privatePort = Integer.parseInt(m.group(3));
Integer publicPort = m.group(2) == null ? null : Integer.parseInt(m.group(2));
String protocol = m.group(5);
if (privatePort <= 0 || privatePort > 65535) {
throw new ClientVisibleException(ResponseCodes.UNPROCESSABLE_ENTITY, INVALID_PRIVATE_PORT);
}
if (publicPort != null && (publicPort <= 0 || publicPort > 65535)) {
throw new ClientVisibleException(ResponseCodes.UNPROCESSABLE_ENTITY, INVALID_PUBLIC_PORT);
}
if (protocol == null) {
protocol = "tcp";
} else {
if (!PROTOCOLS.contains(protocol)) {
throw new ClientVisibleException(ResponseCodes.UNPROCESSABLE_ENTITY, INVALID_PROTOCOL);
}
}
this.ipAddress = ipAddr;
this.publicPort = publicPort;
this.privatePort = privatePort;
this.protocol = protocol;
}
public Integer getPublicPort() {
return publicPort;
}
public int getPrivatePort() {
return privatePort;
}
public String getProtocol() {
return protocol;
}
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
public void setPrivatePort(int privatePort) {
this.privatePort = privatePort;
}
public void setPublicPort(Integer publicPort) {
this.publicPort = publicPort;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public String toSpec() {
String privatePortProto = this.privatePort + (this.protocol != null ? "/" + this.protocol : "");
String publicPort = this.publicPort != null ? this.publicPort.toString() + ":" : "";
String bindIP = "";
if (StringUtils.isNotBlank(this.ipAddress)) {
bindIP = this.ipAddress + ":";
}
return bindIP + publicPort + privatePortProto;
}
@Override
public String toString() {
return toSpec();
}
}