Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,27 @@ public class AgentProperties{
*/
public static final Property<String> KVM_SCRIPTS_DIR = new Property<>("kvm.scripts.dir", "scripts/vm/hypervisor/kvm");

/**
* Name of the systemd template unit used for packet capture of VM NICs.<br>
* The agent starts and stops one instance of this unit per captured NIC, named
* <code>&lt;unit&gt;@&lt;interface&gt;.service</code> (e.g. <code>cloudstack-pcap@vnet3.service</code>).<br>
* When pointing this to a custom unit, make sure the unit reads its environment from
* the file defined by {@link #PACKET_CAPTURE_ENV_DIR}.<br>
* Data type: String.<br>
* Default value: <code>cloudstack-pcap</code>
*/
public static final Property<String> PACKET_CAPTURE_SERVICE = new Property<>("packet.capture.service", "cloudstack-pcap");

/**
* Directory in which the agent writes the environment file for a packet capture,
* named <code>pcap-&lt;interface&gt;.env</code>. The default matches the
* <code>EnvironmentFile=</code> of the shipped cloudstack-pcap@.service unit;
* change both together.<br>
* Data type: String.<br>
* Default value: <code>/run/cloudstack</code>
*/
public static final Property<String> PACKET_CAPTURE_ENV_DIR = new Property<>("packet.capture.env.dir", "/run/cloudstack");

/**
* Specifies start MAC address for private IP range.<br>
* Data type: String.<br>
Expand Down
4 changes: 4 additions & 0 deletions api/src/main/java/com/cloud/event/EventTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ public class EventTypes {
public static final String EVENT_NIC_DETAIL_ADD = "NIC.DETAIL.ADD";
public static final String EVENT_NIC_DETAIL_UPDATE = "NIC.DETAIL.UPDATE";
public static final String EVENT_NIC_DETAIL_REMOVE = "NIC.DETAIL.REMOVE";
public static final String EVENT_NIC_PACKET_CAPTURE_ENABLE = "NIC.PACKETCAPTURE.ENABLE";
public static final String EVENT_NIC_PACKET_CAPTURE_DISABLE = "NIC.PACKETCAPTURE.DISABLE";

// Load Balancers
public static final String EVENT_ASSIGN_TO_LOAD_BALANCER_RULE = "LB.ASSIGN.TO.RULE";
Expand Down Expand Up @@ -980,6 +982,8 @@ public class EventTypes {

// Nic Events
entityEventDetails.put(EVENT_NIC_CREATE, Nic.class);
entityEventDetails.put(EVENT_NIC_PACKET_CAPTURE_ENABLE, Nic.class);
entityEventDetails.put(EVENT_NIC_PACKET_CAPTURE_DISABLE, Nic.class);

// Load Balancers
entityEventDetails.put(EVENT_ASSIGN_TO_LOAD_BALANCER_RULE, FirewallRule.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.command.admin.nic;

import javax.inject.Inject;

import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.NicResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.network.packetcapture.PacketCaptureService;

import com.cloud.event.EventTypes;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.Nic;

@APICommand(name = "disablePacketCapture", responseObject = SuccessResponse.class, entityType = {Nic.class},
responseHasSensitiveInfo = false,
requestHasSensitiveInfo = false,
description = "Disables packet capture on an Instance NIC and stops a running capture. Only supported on KVM.",
authorized = {RoleType.Admin},
since = "4.23.0")
public class DisablePacketCaptureCmd extends BaseAsyncCmd {

@Inject
private PacketCaptureService packetCaptureService;

/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.NIC_ID, type = CommandType.UUID, entityType = NicResponse.class, required = true,
description = "The ID of the NIC to stop capturing packets on")
private Long nicId;

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getNicId() {
return nicId;
}

/////////////////////////////////////////////////////
/////////////////// Implementation //////////////////
/////////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccountId();
}

@Override
public String getEventType() {
return EventTypes.EVENT_NIC_PACKET_CAPTURE_DISABLE;
}

@Override
public String getEventDescription() {
return "Disabling packet capture on NIC with ID: " + getResourceUuid(ApiConstants.NIC_ID);
}

@Override
public void execute() throws ResourceUnavailableException, ServerApiException {
try {
packetCaptureService.disablePacketCapture(getNicId());
SuccessResponse response = new SuccessResponse(getCommandName());
setResponseObject(response);
} catch (CloudRuntimeException e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.command.admin.nic;

import javax.inject.Inject;

import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.NicResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.network.packetcapture.PacketCaptureService;

import com.cloud.event.EventTypes;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.Nic;

@APICommand(name = "enablePacketCapture", responseObject = SuccessResponse.class, entityType = {Nic.class},
responseHasSensitiveInfo = false,
requestHasSensitiveInfo = false,
description = "Enables packet capture on an Instance NIC. The capture is started on the host the Instance " +
"is running on and follows the Instance across stop/start and migration. Only supported on KVM.",
authorized = {RoleType.Admin},
since = "4.23.0")
public class EnablePacketCaptureCmd extends BaseAsyncCmd {

@Inject
private PacketCaptureService packetCaptureService;

/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.NIC_ID, type = CommandType.UUID, entityType = NicResponse.class, required = true,
description = "The ID of the NIC to capture packets on")
private Long nicId;

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getNicId() {
return nicId;
}

/////////////////////////////////////////////////////
/////////////////// Implementation //////////////////
/////////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccountId();
}

@Override
public String getEventType() {
return EventTypes.EVENT_NIC_PACKET_CAPTURE_ENABLE;
}

@Override
public String getEventDescription() {
return "Enabling packet capture on NIC with ID: " + getResourceUuid(ApiConstants.NIC_ID);
}

@Override
public void execute() throws ResourceUnavailableException, ServerApiException {
try {
packetCaptureService.enablePacketCapture(getNicId());
SuccessResponse response = new SuccessResponse(getCommandName());
setResponseObject(response);
} catch (CloudRuntimeException e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.command.admin.nic;

import javax.inject.Inject;

import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.NicResponse;
import org.apache.cloudstack.api.response.PacketCaptureResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.network.packetcapture.PacketCaptureService;

import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.Nic;

@APICommand(name = "getPacketCaptureStatus", responseObject = PacketCaptureResponse.class, entityType = {Nic.class},
responseHasSensitiveInfo = false,
requestHasSensitiveInfo = false,
description = "Returns whether packet capture is enabled on an Instance NIC and whether a capture is " +
"currently running on the host. Only supported on KVM.",
authorized = {RoleType.Admin},
since = "4.23.0")
public class GetPacketCaptureStatusCmd extends BaseCmd {

@Inject
private PacketCaptureService packetCaptureService;

/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.NIC_ID, type = CommandType.UUID, entityType = NicResponse.class, required = true,
description = "The ID of the NIC to get the packet capture status of")
private Long nicId;

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getNicId() {
return nicId;
}

/////////////////////////////////////////////////////
/////////////////// Implementation //////////////////
/////////////////////////////////////////////////////
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccountId();
}

@Override
public void execute() throws ServerApiException {
try {
PacketCaptureResponse response = packetCaptureService.getPacketCaptureStatus(getNicId());
response.setObjectName("packetcapture");
response.setResponseName(getCommandName());
setResponseObject(response);
} catch (CloudRuntimeException e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.response;

import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;

import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;

public class PacketCaptureResponse extends BaseResponse {

@SerializedName(ApiConstants.NIC_ID)
@Param(description = "the ID of the NIC")
private String nicId;

@SerializedName(ApiConstants.VIRTUAL_MACHINE_ID)
@Param(description = "the ID of the Instance the NIC belongs to")
private String virtualMachineId;

@SerializedName(ApiConstants.VIRTUAL_MACHINE_NAME)
@Param(description = "the internal name of the Instance the NIC belongs to")
private String virtualMachineName;

@SerializedName(ApiConstants.MAC_ADDRESS)
@Param(description = "the MAC address of the NIC")
private String macAddress;

@SerializedName(ApiConstants.ENABLED)
@Param(description = "true if packet capture is enabled on the NIC")
private Boolean enabled;

@SerializedName("running")
@Param(description = "true if a packet capture is currently running on the host for the NIC")
private Boolean running;

public void setNicId(String nicId) {
this.nicId = nicId;
}

public void setVirtualMachineId(String virtualMachineId) {
this.virtualMachineId = virtualMachineId;
}

public void setVirtualMachineName(String virtualMachineName) {
this.virtualMachineName = virtualMachineName;
}

public void setMacAddress(String macAddress) {
this.macAddress = macAddress;
}

public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}

public void setRunning(Boolean running) {
this.running = running;
}

public Boolean getEnabled() {
return enabled;
}

public Boolean getRunning() {
return running;
}
}
Loading
Loading