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
CDAP-15588: Prefer internal ip when vpc peering exists #11457
Conversation
String peeredNetwork = matcher.group(4); | ||
if (peeredProjectID.equals(systemProjectId) && peeredNetwork.equals(systemNetwork)) { | ||
if (peering.getState().equals("ACTIVE")) { | ||
// peering to tenant project found prefer internal unless prefer external IP is set |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove comment about "tenant project"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also remove it from the error message and the PR title?
b468983
to
958f1c2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good, but internal language such as "tenant project" should not be here. I see it twice.
958f1c2
to
3c6eaab
Compare
d527eaf
to
528d33a
Compare
@@ -122,6 +133,36 @@ public static DataprocClient fromConf(DataprocConf conf) throws IOException, Gen | |||
String subnet = conf.getSubnet(); | |||
Network networkInfo = getNetworkInfo(projectId, network, compute); | |||
|
|||
// if a peered network is specified then the instance is tied to a network | |||
if (!Strings.isNullOrEmpty(conf.getPeeredNetwork())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we talked about just checking if the configured network is peered with the CDAP network and using the internal IP if so. Are these two new properties (private instance and peered network)actually needed?
// something like 2018-04-16T12:09:03.943-07:00 | ||
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSX"); | ||
|
||
private static final Pattern GCP_NETWORK_FULL_PATH = | ||
Pattern.compile("(https://www.googleapis.com/compute/v1/projects/)(.*)?(/global/networks/)(.*)?"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is 'global' here a location? Is it correct to hardcode it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since its only for comparing with the system network, I think its ok to have hardcode in it as we always create the system network with the global
location. Also in future we may run the cdap services with customer supplied service accounts in which case there is no guarantee that the service account will have access on the system network. Ideally we should pass the system configs to the provisioner so we dont have to have logic of figuring out system network or system project in the Dataproc provisioner itself right?
boolean raiseException) { | ||
List<NetworkPeering> peerings = networkInfo.getPeerings(); | ||
for (NetworkPeering peering : peerings) { | ||
Matcher matcher = GCP_NETWORK_FULL_PATH.matcher(peering.getNetwork()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems safer to get the system network URI and check if it is equal to the peering network rather than parsing this string. Can this be gotten from the Network object corresponding to the system network?
throw new IllegalStateException(String.format("VPC Peering to the system network %s in system project %s found " + | ||
"in INACTIVE state. Please fix peering setup to be in ACTIVE " + | ||
"state.", systemNetwork, systemProjectId)); | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case of private instance which is tied to a network and can only use private ip if the customer has not setup the peering on their end then the peeringState will return NONE in that case internalIP will be preferred unless someone set externalIP to true but the run will fail since there is no peering from customer side.
I believe we will have to ensure that the peering does exist when instance is private.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please open a bug for this .
@@ -59,6 +60,8 @@ | |||
|
|||
// Keys for looking up system properties | |||
private static final String LABELS_PROPERTY = "labels"; | |||
// Name of the network on customer project where the Dataproc cluster is to be created | |||
private static final String NETWORK = "network"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unused.
e1c740d
to
febb386
Compare
PeeringState state = peeringState(systemNetwork, systemProjectId, networkInfo); | ||
if (state == PeeringState.ACTIVE) { | ||
if (conf.isPreferExternalIP()) { | ||
LOG.warn("Prefer external IP setting will be ignored and internal IP will used to communicate with the " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not be making an assumption that the user has misconfigured this property. If a user is explicitly telling the provisioner to use the external IP, it should always use the external IP, regardless of how the network is setup. We can log an INFO message that the network is peered and suggest that the internal IP be used, but we should not override something they have explicitly set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
@@ -149,6 +178,27 @@ public static DataprocClient fromConf(DataprocConf conf) throws IOException, Gen | |||
return new DataprocClient(new DataprocConf(conf, network, subnet), client, compute, useInternalIP); | |||
} | |||
|
|||
private static PeeringState peeringState(String systemNetwork, String systemProjectId, Network networkInfo) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the system network is nullable. It is null when CDAP is not running on GCP. When null, there is no peering between CDAP and the configured network.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added @Nullable
annotation and corresponding check.
|
||
String peeredProjectID = matcher.group(2); | ||
String peeredNetwork = matcher.group(4); | ||
if (peeredProjectID.equals(systemProjectId) && peeredNetwork.equals(systemNetwork)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned previously, we should not be using pattern matching for this. The Network object for the system network can be fetched and used to check equality. The global location should not be hardcoded either, as it should be known from the Network object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed the pattern matching code.
@@ -263,6 +313,11 @@ public OperationSnapshot createCluster(String name, String imageVersion, Map<Str | |||
clusterConfig.addTags(targetTag); | |||
} | |||
|
|||
// if internal ip is prefered then create dataproc cluster without external ip for better security | |||
if (!conf.isPreferExternalIP()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not correct, it will create internal IP clusters in many instances where CDAP requires the external IP. This should be using the useInternalIP flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
...ext-dataproc/src/main/java/io/cdap/cdap/runtime/spi/provisioner/dataproc/DataprocClient.java
Show resolved
Hide resolved
@@ -18,6 +18,7 @@ | |||
|
|||
import com.google.common.annotations.VisibleForTesting; | |||
import com.google.common.base.Splitter; | |||
import com.google.common.base.Strings; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
accidental addition?
} | ||
useInternalIP = true; | ||
} else if (state == PeeringState.INACTIVE) { | ||
throw new IllegalStateException(String.format("VPC Peering to the system network %s in system project %s found " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should include the dataproc network being used.
VPC Peering from network '%s' in project '%s' to network '%s' in project '%s' is in the INACTIVE state. Please fix the peering setup to be in the ACTIVE state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.
"in INACTIVE state. Please fix peering setup to be in ACTIVE " + | ||
"state.", systemNetwork, systemProjectId)); | ||
} else { | ||
useInternalIP = !conf.isPreferExternalIP(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not correct. This setting is used to tell the provisioner to use the external IP even when it detects that the internal IP can be used. When this is false and the provisioner detects that the internal IP cant be used (when the system network does not exist or is different than the dataproc network and it is not peered), useInternalIP should be false.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done. so conf.isPreferExternalIP()
takes precedence.
// Get self link for the network. | ||
String systemNetworkSelfLink = systemNetworkInfo.getSelfLink(); | ||
|
||
LOG.info(String.format("Self link for the system network is %s", systemNetworkSelfLink)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added log line for debugging purpose. Will remove before merging.
@@ -122,6 +129,32 @@ public static DataprocClient fromConf(DataprocConf conf) throws IOException, Gen | |||
String subnet = conf.getSubnet(); | |||
Network networkInfo = getNetworkInfo(projectId, network, compute); | |||
|
|||
boolean useInternalIP = !conf.isPreferExternalIP(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this isn't correct. use internal IP should only be true if:
prefer external IP is false
AND
(system network is the same as the dataproc network) OR (system network is peered with dataproc network)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated code as discussed.
comment about unused import still exists too |
"(Prefer External IP = false) Dataproc clusters.", | ||
systemProjectId, projectId)); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
boolean useInternalIP = !conf.isPreferExternalIP() && (sytemNetwork.equals(network) || PeeringState.ACTIVE == state)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
@albertshau please take a look again. thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm pending removal of debugging statement.
072c9d5
to
6459fc7
Compare
Build is running here - https://builds.cask.co/browse/CDAP-DUT6996-9 |
return PeeringState.NONE; | ||
} | ||
|
||
Network systemNetworkInfo = getNetworkInfo(systemProjectId, systemNetwork, compute); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This requires permission on the network which is acceptable but will not be present on existing setups and will require backfill.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sagarkapare : Thinking more about this permission issue change it has a much wider impact. This requires the management SA to have network permission on the tp network. In Beta it does not which means that for existing customer if we roll out this change the dataproc provisioning will start failing for all instances till the permissions are backfilled.
// Peering is setup between the system network and customer network. However it is not in ACTIVE state. | ||
// User has also intended to use the internal IP. Dataproc cluster cannot be launched on the internal IP unless | ||
// the peering is fixed. | ||
} else if (!conf.isPreferExternalIP() && state != PeeringState.ACTIVE) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this was correct before and incorrect now. "Prefer External IP" just means always use the external ip if it is true. If it is false, let the provisioner decide. A false value does not mean always use the internal ip.
} | ||
} | ||
|
||
private static PeeringState peeringState(@Nullable String systemNetwork, String systemProjectId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be called getPeeringState
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
LOG.info(String.format("Self link for the system network is %s", systemNetworkSelfLink)); | ||
List<NetworkPeering> peerings = networkInfo.getPeerings(); | ||
// if the customer does not has a peering established at all the peering list is null | ||
if (peerings != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Invert the check and return early. It makes the code cleaner and easier to reason all the states.
if (peerings == null) {
return PeeringState.NONE;
}
for (...) {
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
if (!systemNetworkSelfLink.equals(peering.getNetwork())) { | ||
continue; | ||
} | ||
if (peering.getState().equals("ACTIVE")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the ? :
operator will make the logic easier to read.
return peering.getState().equals("ACTIVE") ? PeeringState.ACTIVE : PeeringState.INACTIVE;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
...ext-dataproc/src/main/java/io/cdap/cdap/runtime/spi/provisioner/dataproc/DataprocClient.java
Outdated
Show resolved
Hide resolved
// However user has selected to preferred external IP the instance. This is not a private instance and is | ||
// capable of communicating with Dataproc cluster with external ip so just add warning message indicating that | ||
// internal IP can be used. | ||
LOG.warn(String.format("VPC Peering from network '%s' in project '%s' to network '%s' " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is more like an INFO rather than warning.
// (CDAP is running in the same customer project as Dataproc is going to be launched or | ||
// Network peering is done between customer network and system network and is in ACTIVE mode). | ||
useInternalIP = !conf.isPreferExternalIP() | ||
&& ((network.equals(systemNetwork) && projectId.equals(systemProjectId)) || state == PeeringState.ACTIVE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the systemNetwork the GCP network that CDAP itself is using? If that's the case, why it has to be the same as the Dataproc network?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes this check is there for EAP and other setup where it runs in customer project.
...ext-dataproc/src/main/java/io/cdap/cdap/runtime/spi/provisioner/dataproc/DataprocClient.java
Show resolved
Hide resolved
...ext-dataproc/src/main/java/io/cdap/cdap/runtime/spi/provisioner/dataproc/DataprocClient.java
Outdated
Show resolved
Hide resolved
...ext-dataproc/src/main/java/io/cdap/cdap/runtime/spi/provisioner/dataproc/DataprocClient.java
Outdated
Show resolved
Hide resolved
...ext-dataproc/src/main/java/io/cdap/cdap/runtime/spi/provisioner/dataproc/DataprocClient.java
Outdated
Show resolved
Hide resolved
...ext-dataproc/src/main/java/io/cdap/cdap/runtime/spi/provisioner/dataproc/DataprocClient.java
Outdated
Show resolved
Hide resolved
...ext-dataproc/src/main/java/io/cdap/cdap/runtime/spi/provisioner/dataproc/DataprocClient.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
Waiting on build: https://builds.cask.co/browse/CDAP-DUT6996-13 |
Build passed merging. |
0c6df95
to
5e9fb76
Compare
|
||
if (privateInstance) { | ||
// private instance must have a peering established | ||
verifyPeering(conf, network, systemNetwork, projectId, systemProjectId, state); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove the peering check. What we need is connectivity in some form, and is not necessarily achieved via network peering
…t network prefer internal ip