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

CDAP-15588: Prefer internal ip when vpc peering exists #11457

Merged
merged 8 commits into from Jul 11, 2019

Conversation

rohitsinha54
Copy link
Contributor

@rohitsinha54 rohitsinha54 commented Jun 27, 2019

…t network prefer internal ip

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
Copy link
Contributor

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"

Copy link
Contributor

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?

Copy link
Contributor

@anew anew left a 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.

@rohitsinha54 rohitsinha54 reopened this Jun 28, 2019
@rohitsinha54 rohitsinha54 force-pushed the feature/CDAP-15588-private branch 2 times, most recently from d527eaf to 528d33a Compare June 28, 2019 05:07
@rohitsinha54 rohitsinha54 changed the title CDAP-15588: Private instance - if customer network is peered to tenan… CDAP-15588: Prefer internal ip when vpc peering exists Jun 28, 2019
@@ -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())) {
Copy link
Contributor

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/)(.*)?");
Copy link
Contributor

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?

Copy link
Contributor

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());
Copy link
Contributor

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 {
Copy link
Contributor Author

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.

Copy link
Contributor Author

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";
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is unused.

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 " +
Copy link
Contributor

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.

Copy link
Contributor

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) {
Copy link
Contributor

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.

Copy link
Contributor

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)) {
Copy link
Contributor

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.

Copy link
Contributor

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()) {
Copy link
Contributor

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.

Copy link
Contributor

Choose a reason for hiding this comment

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

fixed.

@@ -18,6 +18,7 @@

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
Copy link
Contributor

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 " +
Copy link
Contributor

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.

Copy link
Contributor

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();
Copy link
Contributor

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.

Copy link
Contributor

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));
Copy link
Contributor

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();
Copy link
Contributor

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)

Copy link
Contributor

Choose a reason for hiding this comment

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

updated code as discussed.

@albertshau
Copy link
Contributor

comment about unused import still exists too

"(Prefer External IP = false) Dataproc clusters.",
systemProjectId, projectId));
}

Copy link
Contributor

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)

Copy link
Contributor

Choose a reason for hiding this comment

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

done.

@sagarkapare
Copy link
Contributor

@albertshau please take a look again. thanks!

Copy link
Contributor

@albertshau albertshau left a 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.

@sagarkapare
Copy link
Contributor

Build is running here - https://builds.cask.co/browse/CDAP-DUT6996-9

return PeeringState.NONE;
}

Network systemNetworkInfo = getNetworkInfo(systemProjectId, systemNetwork, compute);
Copy link
Contributor Author

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.

Copy link
Contributor Author

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) {
Copy link
Contributor

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,
Copy link
Contributor

Choose a reason for hiding this comment

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

Should be called getPeeringState.

Copy link
Contributor Author

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) {
Copy link
Contributor

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 (...) {
}

Copy link
Contributor Author

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")) {
Copy link
Contributor

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;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

// 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' " +
Copy link
Contributor

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);
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

@albertshau albertshau left a comment

Choose a reason for hiding this comment

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

lgtm

@rohitsinha54
Copy link
Contributor Author

Waiting on build: https://builds.cask.co/browse/CDAP-DUT6996-13

@rohitsinha54 rohitsinha54 requested a review from chtyim July 10, 2019 23:12
@rohitsinha54
Copy link
Contributor Author

Build passed merging.


if (privateInstance) {
// private instance must have a peering established
verifyPeering(conf, network, systemNetwork, projectId, systemProjectId, state);
Copy link
Contributor

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

@rohitsinha54 rohitsinha54 merged commit 8cc4949 into release/6.0 Jul 11, 2019
@chtyim chtyim deleted the feature/CDAP-15588-private branch August 19, 2019 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
6 participants