/**
   * Applies the given security group permissions to the given node with the given compute service.
   *
   * <p>Takes no action if the compute service does not have a security group extension.
   *
   * @param permissions The set of permissions to be applied to the node
   * @param nodeId The id of the node to update
   * @param computeService The compute service to use to apply the changes
   */
  @VisibleForTesting
  Map<String, SecurityGroup> addPermissionsToLocation(
      Iterable<IpPermission> permissions, final String nodeId, ComputeService computeService) {
    if (!computeService.getSecurityGroupExtension().isPresent()) {
      LOG.warn(
          "Security group extension for {} absent; cannot update node {} with {}",
          new Object[] {computeService, nodeId, permissions});
      return ImmutableMap.of();
    }
    final SecurityGroupExtension securityApi = computeService.getSecurityGroupExtension().get();
    final String locationId = computeService.getContext().unwrap().getId();

    // Expect to have two security groups on the node: one shared between all nodes in the location,
    // that is cached in sharedGroupCache, and one created by Jclouds that is unique to the node.
    // Relies on customize having been called before. This should be safe because the arguments
    // needed to call this method are not available until post-instance creation.
    SecurityGroup machineUniqueSecurityGroup = getSecurityGroup(nodeId, securityApi, locationId);
    MutableList<IpPermission> newPermissions = MutableList.copyOf(permissions);
    Iterables.removeAll(newPermissions, machineUniqueSecurityGroup.getIpPermissions());
    MutableMap<String, SecurityGroup> addedSecurityGroups = MutableMap.of();
    for (IpPermission permission : newPermissions) {
      SecurityGroup addedPermission =
          addPermission(permission, machineUniqueSecurityGroup, securityApi);
      addedSecurityGroups.put(addedPermission.getId(), addedPermission);
    }
    return addedSecurityGroups;
  }