Use metadata secret var in openstack node, support PUT/POST/DELETE

Change-Id: Id744b6443b49a3a0e73f9d497462f48ba64ab0a7
This commit is contained in:
Jian Li 2018-09-04 23:52:11 +09:00
parent c704b67f87
commit 4665093b0f
2 changed files with 74 additions and 45 deletions

View File

@ -16,13 +16,11 @@
package org.onosproject.openstacknetworking.impl; package org.onosproject.openstacknetworking.impl;
import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Modified;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.http.Header; import org.apache.http.Header;
@ -31,8 +29,10 @@ import org.apache.http.HttpMessage;
import org.apache.http.HttpRequest; import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClientBuilder;
@ -46,8 +46,6 @@ import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix; import org.onlab.packet.IpPrefix;
import org.onlab.packet.TCP; import org.onlab.packet.TCP;
import org.onlab.packet.TpPort; import org.onlab.packet.TpPort;
import org.onlab.util.Tools;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.cluster.ClusterService; import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.LeadershipService; import org.onosproject.cluster.LeadershipService;
import org.onosproject.cluster.NodeId; import org.onosproject.cluster.NodeId;
@ -72,13 +70,12 @@ import org.onosproject.openstacknode.api.OpenstackNodeEvent;
import org.onosproject.openstacknode.api.OpenstackNodeListener; import org.onosproject.openstacknode.api.OpenstackNodeListener;
import org.onosproject.openstacknode.api.OpenstackNodeService; import org.onosproject.openstacknode.api.OpenstackNodeService;
import org.openstack4j.model.network.Port; import org.openstack4j.model.network.Port;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger; import org.slf4j.Logger;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Dictionary;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import static org.onosproject.openstacknetworking.api.Constants.DHCP_ARP_TABLE; import static org.onosproject.openstacknetworking.api.Constants.DHCP_ARP_TABLE;
import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_DHCP_RULE; import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_DHCP_RULE;
@ -121,16 +118,12 @@ public class OpenstackMetadataProxyHandler {
private static final String HTTP_GET_METHOD = "GET"; private static final String HTTP_GET_METHOD = "GET";
private static final String HTTP_POST_METHOD = "POST"; private static final String HTTP_POST_METHOD = "POST";
private static final String HTTP_PUT_METHOD = "PUT";
private static final String METADATA_SECRET = "metadataSecret"; private static final String HTTP_DELETE_METHOD = "DELETE";
private static final String DEFAULT_METADATA_SECRET = "nova";
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService; protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ComponentConfigService configService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PacketService packetService; protected PacketService packetService;
@ -152,13 +145,11 @@ public class OpenstackMetadataProxyHandler {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected OpenstackFlowRuleService osFlowRuleService; protected OpenstackFlowRuleService osFlowRuleService;
@Property(name = METADATA_SECRET, value = DEFAULT_METADATA_SECRET,
label = "Metadata secret")
private String metadataSecret = DEFAULT_METADATA_SECRET;
private final PacketProcessor packetProcessor = new InternalPacketProcessor(); private final PacketProcessor packetProcessor = new InternalPacketProcessor();
private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener(); private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
private Set<String> excludedHeaders = ImmutableSet.of("content-type", "content-length");
private ApplicationId appId; private ApplicationId appId;
private NodeId localNodeId; private NodeId localNodeId;
@ -166,7 +157,6 @@ public class OpenstackMetadataProxyHandler {
protected void activate() { protected void activate() {
appId = coreService.registerApplication(Constants.OPENSTACK_NETWORKING_APP_ID); appId = coreService.registerApplication(Constants.OPENSTACK_NETWORKING_APP_ID);
localNodeId = clusterService.getLocalNode().id(); localNodeId = clusterService.getLocalNode().id();
configService.registerProperties(getClass());
osNodeService.addListener(osNodeListener); osNodeService.addListener(osNodeListener);
packetService.addProcessor(packetProcessor, PacketProcessor.director(0)); packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
leadershipService.runForLeadership(appId.name()); leadershipService.runForLeadership(appId.name());
@ -177,32 +167,21 @@ public class OpenstackMetadataProxyHandler {
@Deactivate @Deactivate
protected void deactivate() { protected void deactivate() {
packetService.removeProcessor(packetProcessor); packetService.removeProcessor(packetProcessor);
configService.unregisterProperties(getClass(), false);
osNodeService.removeListener(osNodeListener); osNodeService.removeListener(osNodeListener);
leadershipService.withdraw(appId.name()); leadershipService.withdraw(appId.name());
log.info("Stopped"); log.info("Stopped");
} }
@Modified
protected void modified(ComponentContext context) {
Dictionary<?, ?> properties = context.getProperties();
String updatedMetadataSecret;
updatedMetadataSecret = Tools.get(properties, METADATA_SECRET);
if (!Strings.isNullOrEmpty(updatedMetadataSecret) &&
!updatedMetadataSecret.equals(metadataSecret)) {
metadataSecret = updatedMetadataSecret;
}
log.info("Modified");
}
private class InternalPacketProcessor implements PacketProcessor { private class InternalPacketProcessor implements PacketProcessor {
@Override @Override
public void process(PacketContext context) { public void process(PacketContext context) {
if (!useMetadataProxy()) {
return;
}
if (context.isHandled()) { if (context.isHandled()) {
return; return;
} }
@ -224,12 +203,16 @@ public class OpenstackMetadataProxyHandler {
return; return;
} }
// (three-way handshaking)
// reply TCP SYN-ACK packet with receiving TCP SYN packet
if (tcpPacket.getFlags() == SYN_FLAG) { if (tcpPacket.getFlags() == SYN_FLAG) {
Ethernet ethReply = buildTcpSynAckPacket(ethPacket, ipv4Packet, tcpPacket); Ethernet ethReply = buildTcpSynAckPacket(ethPacket, ipv4Packet, tcpPacket);
sendReply(context, ethReply); sendReply(context, ethReply);
return; return;
} }
// (four-way handshaking)
// reply TCP ACK and TCP FIN-ACK packets with receiving TCP FIN-ACK packet
if (tcpPacket.getFlags() == FIN_ACK_FLAG) { if (tcpPacket.getFlags() == FIN_ACK_FLAG) {
Ethernet ackReply = buildTcpAckPacket(ethPacket, ipv4Packet, tcpPacket); Ethernet ackReply = buildTcpAckPacket(ethPacket, ipv4Packet, tcpPacket);
sendReply(context, ackReply); sendReply(context, ackReply);
@ -238,6 +221,7 @@ public class OpenstackMetadataProxyHandler {
return; return;
} }
// normal TCP data transmission
Data data = (Data) tcpPacket.getPayload(); Data data = (Data) tcpPacket.getPayload();
byte[] byteData = data.getData(); byte[] byteData = data.getData();
@ -252,7 +236,7 @@ public class OpenstackMetadataProxyHandler {
} }
// attempt to send HTTP request to the meta-data server (nova-api), // attempt to send HTTP request to the meta-data server (nova-api),
// obtain the HTTP response // obtain the HTTP response, relay the response to VM through packet-out
CloseableHttpResponse proxyResponse = proxyHttpRequest(request, instPort); CloseableHttpResponse proxyResponse = proxyHttpRequest(request, instPort);
if (proxyResponse == null) { if (proxyResponse == null) {
@ -434,19 +418,30 @@ public class OpenstackMetadataProxyHandler {
return null; return null;
} }
log.info("Sending request to metadata endpoint {}...", url);
HttpRequestBase request; HttpRequestBase request;
switch (oldRequest.getRequestLine().getMethod()) { String method = oldRequest.getRequestLine().getMethod().toUpperCase();
log.info("Sending HTTP {} request to metadata endpoint {}...", method, url);
switch (method) {
case HTTP_GET_METHOD: case HTTP_GET_METHOD:
request = new HttpGet(url); request = new HttpGet(url);
break; break;
case HTTP_POST_METHOD: case HTTP_POST_METHOD:
request = new HttpPost(url); request = new HttpPost(url);
HttpEntityEnclosingRequest entityRequest = HttpEntityEnclosingRequest postRequest =
(HttpEntityEnclosingRequest) oldRequest; (HttpEntityEnclosingRequest) oldRequest;
((HttpPost) request).setEntity(entityRequest.getEntity()); ((HttpPost) request).setEntity(postRequest.getEntity());
break;
case HTTP_PUT_METHOD:
request = new HttpPut(url);
HttpEntityEnclosingRequest putRequest =
(HttpEntityEnclosingRequest) oldRequest;
((HttpPut) request).setEntity(putRequest.getEntity());
break;
case HTTP_DELETE_METHOD:
request = new HttpDelete(url);
break; break;
default: default:
request = new HttpGet(url); request = new HttpGet(url);
@ -455,6 +450,13 @@ public class OpenstackMetadataProxyHandler {
// configure headers from original HTTP request // configure headers from original HTTP request
for (Header header : oldRequest.getAllHeaders()) { for (Header header : oldRequest.getAllHeaders()) {
if (method.equals(HTTP_POST_METHOD) ||
method.equals(HTTP_PUT_METHOD)) {
// we DO NOT add duplicated HTTP headers for POST and PUT methods
if (excludedHeaders.contains(header.getName().toLowerCase())) {
continue;
}
}
request.addHeader(header); request.addHeader(header);
} }
@ -463,11 +465,12 @@ public class OpenstackMetadataProxyHandler {
Port port = osNetworkService.port(instPort.portId()); Port port = osNetworkService.port(instPort.portId());
request.addHeader(new BasicHeader(INSTANCE_ID_HEADER, port.getDeviceId())); request.addHeader(new BasicHeader(INSTANCE_ID_HEADER, port.getDeviceId()));
request.addHeader(new BasicHeader(INSTANCE_ID_SIGNATURE_HEADER,
hmacEncrypt(metadataSecret, port.getDeviceId())));
request.addHeader(new BasicHeader(TENANT_ID_HEADER, port.getTenantId())); request.addHeader(new BasicHeader(TENANT_ID_HEADER, port.getTenantId()));
request.addHeader(new BasicHeader( request.addHeader(new BasicHeader(FORWARDED_FOR_HEADER, instPort.ipAddress().toString()));
FORWARDED_FOR_HEADER, instPort.ipAddress().toString())); if (metadataSecret() != null) {
request.addHeader(new BasicHeader(INSTANCE_ID_SIGNATURE_HEADER,
hmacEncrypt(metadataSecret(), port.getDeviceId())));
}
try { try {
return client.execute(request); return client.execute(request);
@ -508,7 +511,7 @@ public class OpenstackMetadataProxyHandler {
// do not allow to proceed without leadership // do not allow to proceed without leadership
NodeId leader = leadershipService.getLeader(appId.name()); NodeId leader = leadershipService.getLeader(appId.name());
return Objects.equals(localNodeId, leader) && return Objects.equals(localNodeId, leader) &&
event.subject().type() == COMPUTE; event.subject().type() == COMPUTE && useMetadataProxy();
} }
@Override @Override
@ -559,6 +562,28 @@ public class OpenstackMetadataProxyHandler {
} }
} }
private boolean useMetadataProxy() {
OpenstackNode gw = osNodeService.completeNodes(CONTROLLER)
.stream().findFirst().orElse(null);
if (gw != null && gw.neutronConfig() != null) {
return gw.neutronConfig().useMetadataProxy();
}
return false;
}
private String metadataSecret() {
OpenstackNode controller = osNodeService.completeNodes(CONTROLLER)
.stream().findFirst().orElse(null);
if (controller != null && controller.neutronConfig() != null) {
return controller.neutronConfig().metadataProxySecret();
}
return null;
}
/** /**
* Implements Http packet format. * Implements Http packet format.
*/ */

View File

@ -26,6 +26,8 @@ import org.onlab.util.KryoNamespace;
import org.onosproject.core.ApplicationId; import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService; import org.onosproject.core.CoreService;
import org.onosproject.net.behaviour.ControllerInfo; import org.onosproject.net.behaviour.ControllerInfo;
import org.onosproject.openstacknode.api.DefaultKeystoneConfig;
import org.onosproject.openstacknode.api.DefaultNeutronConfig;
import org.onosproject.openstacknode.api.DefaultOpenstackAuth; import org.onosproject.openstacknode.api.DefaultOpenstackAuth;
import org.onosproject.openstacknode.api.DefaultOpenstackNode; import org.onosproject.openstacknode.api.DefaultOpenstackNode;
import org.onosproject.openstacknode.api.DpdkConfig; import org.onosproject.openstacknode.api.DpdkConfig;
@ -98,6 +100,8 @@ public class DistributedOpenstackNodeStore
.register(DefaultOpenstackAuth.Perspective.class) .register(DefaultOpenstackAuth.Perspective.class)
.register(DefaultOpenstackAuth.Protocol.class) .register(DefaultOpenstackAuth.Protocol.class)
.register(DefaultOpenstackSshAuth.class) .register(DefaultOpenstackSshAuth.class)
.register(DefaultKeystoneConfig.class)
.register(DefaultNeutronConfig.class)
.register(Collection.class) .register(Collection.class)
.build(); .build();