You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by sh...@apache.org on 2018/11/24 21:56:56 UTC
[07/50] [abbrv] hadoop git commit: YARN-8881. [YARN-8851] Add basic
pluggable device plugin framework. (Zhankun Tang via wangda)
YARN-8881. [YARN-8851] Add basic pluggable device plugin framework. (Zhankun Tang via wangda)
Change-Id: If9a2f68cd4713b4ec932cdeda68106f17437c3d3
Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/63578036
Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/63578036
Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/63578036
Branch: refs/heads/HDFS-12943
Commit: 63578036450f660d49ae204327efcd629d9dd137
Parents: 9366608
Author: Wangda Tan <wa...@apache.org>
Authored: Mon Nov 19 08:54:31 2018 -0800
Committer: Wangda Tan <wa...@apache.org>
Committed: Mon Nov 19 08:54:31 2018 -0800
----------------------------------------------------------------------
.../nodemanager/api/deviceplugin/Device.java | 233 +++++++++++++++++++
.../api/deviceplugin/DevicePlugin.java | 65 ++++++
.../api/deviceplugin/DeviceRegisterRequest.java | 73 ++++++
.../api/deviceplugin/DeviceRuntimeSpec.java | 137 +++++++++++
.../api/deviceplugin/MountDeviceSpec.java | 131 +++++++++++
.../api/deviceplugin/MountVolumeSpec.java | 118 ++++++++++
.../api/deviceplugin/VolumeSpec.java | 114 +++++++++
.../api/deviceplugin/YarnRuntimeType.java | 42 ++++
.../api/deviceplugin/package-info.java | 19 ++
.../resourceplugin/ResourcePluginManager.java | 116 ++++++++-
.../deviceframework/DevicePluginAdapter.java | 88 +++++++
.../DeviceResourceUpdaterImpl.java | 66 ++++++
.../deviceframework/package-info.java | 19 ++
.../resourceplugin/package-info.java | 19 ++
.../TestResourcePluginManager.java | 169 +++++++++++++-
.../deviceframework/FakeTestDevicePlugin1.java | 61 +++++
.../deviceframework/FakeTestDevicePlugin2.java | 27 +++
.../deviceframework/FakeTestDevicePlugin3.java | 65 ++++++
.../deviceframework/FakeTestDevicePlugin4.java | 54 +++++
.../TestDevicePluginAdapter.java | 145 ++++++++++++
.../resource-types-pluggable-devices.xml | 23 ++
21 files changed, 1773 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/Device.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/Device.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/Device.java
new file mode 100644
index 0000000..551c2d8
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/Device.java
@@ -0,0 +1,233 @@
+/**
+ * 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.hadoop.yarn.server.nodemanager.api.deviceplugin;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * Represent one "device" resource.
+ * */
+public final class Device implements Serializable, Comparable {
+
+ private static final long serialVersionUID = -7270474563684671656L;
+
+ /**
+ * An plugin specified index number.
+ * Must set. Recommend starting from 0
+ * */
+ private final int id;
+
+ /**
+ * The device node like "/dev/devname".
+ * Optional
+ * */
+ private final String devPath;
+
+ /**
+ * The major device number.
+ * Optional
+ * */
+ private final int majorNumber;
+
+ /**
+ * The minor device number.
+ * Optional
+ * */
+ private final int minorNumber;
+
+ /**
+ * PCI Bus ID in format [[[[<domain>]:]<bus>]:][<slot>][.[<func>]].
+ * Optional. Can get from "lspci -D" in Linux
+ * */
+ private final String busID;
+
+ /**
+ * Is healthy or not.
+ * false by default
+ * */
+ private boolean isHealthy;
+
+ /**
+ * Plugin customized status info.
+ * Optional
+ * */
+ private String status;
+
+ /**
+ * Private constructor.
+ * @param builder
+ */
+ private Device(Builder builder) {
+ if (builder.id == -1) {
+ throw new IllegalArgumentException("Please set the id for Device");
+ }
+ this.id = builder.id;
+ this.devPath = builder.devPath;
+ this.majorNumber = builder.majorNumber;
+ this.minorNumber = builder.minorNumber;
+ this.busID = builder.busID;
+ this.isHealthy = builder.isHealthy;
+ this.status = builder.status;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public String getDevPath() {
+ return devPath;
+ }
+
+ public int getMajorNumber() {
+ return majorNumber;
+ }
+
+ public int getMinorNumber() {
+ return minorNumber;
+ }
+
+ public String getBusID() {
+ return busID;
+ }
+
+ public boolean isHealthy() {
+ return isHealthy;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Device device = (Device) o;
+ return id == device.getId()
+ && Objects.equals(devPath, device.getDevPath())
+ && majorNumber == device.getMajorNumber()
+ && minorNumber == device.getMinorNumber()
+ && Objects.equals(busID, device.getBusID());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, devPath, majorNumber, minorNumber, busID);
+ }
+
+ @Override
+ public int compareTo(Object o) {
+ if (o == null || (!(o instanceof Device))) {
+ return -1;
+ }
+
+ Device other = (Device) o;
+
+ int result = Integer.compare(id, other.getId());
+ if (0 != result) {
+ return result;
+ }
+
+ result = Integer.compare(majorNumber, other.getMajorNumber());
+ if (0 != result) {
+ return result;
+ }
+
+ result = Integer.compare(minorNumber, other.getMinorNumber());
+ if (0 != result) {
+ return result;
+ }
+
+ result = devPath.compareTo(other.getDevPath());
+ if (0 != result) {
+ return result;
+ }
+
+ return busID.compareTo(other.getBusID());
+ }
+
+ @Override
+ public String toString() {
+ return "(" + getId() + ", " + getDevPath() + ", "
+ + getMajorNumber() + ":" + getMinorNumber() + ")";
+ }
+
+ /**
+ * Builder for Device.
+ * */
+ public final static class Builder {
+ // default -1 representing the value is not set
+ private int id = -1;
+ private String devPath = "";
+ private int majorNumber;
+ private int minorNumber;
+ private String busID = "";
+ private boolean isHealthy;
+ private String status = "";
+
+ public static Builder newInstance() {
+ return new Builder();
+ }
+
+ public Device build() {
+ return new Device(this);
+ }
+
+ public Builder setId(int i) {
+ this.id = i;
+ return this;
+ }
+
+ public Builder setDevPath(String dp) {
+ this.devPath = dp;
+ return this;
+ }
+
+ public Builder setMajorNumber(int maN) {
+ this.majorNumber = maN;
+ return this;
+ }
+
+ public Builder setMinorNumber(int miN) {
+ this.minorNumber = miN;
+ return this;
+ }
+
+ public Builder setBusID(String bI) {
+ this.busID = bI;
+ return this;
+ }
+
+ public Builder setHealthy(boolean healthy) {
+ isHealthy = healthy;
+ return this;
+ }
+
+ public Builder setStatus(String s) {
+ this.status = s;
+ return this;
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/DevicePlugin.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/DevicePlugin.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/DevicePlugin.java
new file mode 100644
index 0000000..5b7a569
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/DevicePlugin.java
@@ -0,0 +1,65 @@
+/**
+ * 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.hadoop.yarn.server.nodemanager.api.deviceplugin;
+
+import java.util.Set;
+
+/**
+ * A must interface for vendor plugin to implement.
+ * */
+public interface DevicePlugin {
+ /**
+ * Called first when device plugin framework wants to register.
+ * @return DeviceRegisterRequest {@link DeviceRegisterRequest}
+ * */
+ DeviceRegisterRequest getRegisterRequestInfo()
+ throws Exception;
+
+ /**
+ * Called when update node resource.
+ * @return a set of {@link Device}, {@link java.util.TreeSet} recommended
+ * */
+ Set<Device> getDevices() throws Exception;
+
+ /**
+ * Asking how these devices should be prepared/used
+ * before/when container launch. A plugin can do some tasks in its own or
+ * define it in DeviceRuntimeSpec to let the framework do it.
+ * For instance, define {@code VolumeSpec} to let the
+ * framework to create volume before running container.
+ *
+ * @param allocatedDevices A set of allocated {@link Device}.
+ * @param yarnRuntime Indicate which runtime YARN will use
+ * Could be {@code RUNTIME_DEFAULT} or {@code RUNTIME_DOCKER}
+ * in {@link DeviceRuntimeSpec} constants. The default means YARN's
+ * non-docker container runtime is used. The docker means YARN's
+ * docker container runtime is used.
+ * @return a {@link DeviceRuntimeSpec} description about environment,
+ * {@link VolumeSpec}, {@link MountVolumeSpec}. etc
+ * */
+ DeviceRuntimeSpec onDevicesAllocated(Set<Device> allocatedDevices,
+ YarnRuntimeType yarnRuntime) throws Exception;
+
+ /**
+ * Called after device released.
+ * @param releasedDevices A set of released devices
+ * */
+ void onDevicesReleased(Set<Device> releasedDevices)
+ throws Exception;
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/DeviceRegisterRequest.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/DeviceRegisterRequest.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/DeviceRegisterRequest.java
new file mode 100644
index 0000000..8fbff88
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/DeviceRegisterRequest.java
@@ -0,0 +1,73 @@
+/**
+ * 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.hadoop.yarn.server.nodemanager.api.deviceplugin;
+
+import java.util.Objects;
+
+/**
+ * Contains plugin register request info.
+ * */
+public final class DeviceRegisterRequest {
+
+ // plugin's own version
+ private final String pluginVersion;
+ private final String resourceName;
+
+ private DeviceRegisterRequest(Builder builder) {
+ this.resourceName = Objects.requireNonNull(builder.resourceName);
+ this.pluginVersion = builder.pluginVersion;
+ }
+
+ public String getResourceName() {
+ return resourceName;
+ }
+
+ public String getPluginVersion() {
+ return pluginVersion;
+ }
+
+ /**
+ * Builder class for construct {@link DeviceRegisterRequest}.
+ * */
+ public final static class Builder {
+ private String pluginVersion;
+ private String resourceName;
+
+ private Builder() {}
+
+ public static Builder newInstance() {
+ return new Builder();
+ }
+
+ public DeviceRegisterRequest build() {
+ return new DeviceRegisterRequest(this);
+ }
+
+ public Builder setResourceName(String resName) {
+ this.resourceName = resName;
+ return this;
+ }
+
+ public Builder setPluginVersion(String plVersion) {
+ this.pluginVersion = plVersion;
+ return this;
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/DeviceRuntimeSpec.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/DeviceRuntimeSpec.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/DeviceRuntimeSpec.java
new file mode 100644
index 0000000..32bd593
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/DeviceRuntimeSpec.java
@@ -0,0 +1,137 @@
+/**
+ * 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.hadoop.yarn.server.nodemanager.api.deviceplugin;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * This is a spec used to prepare & run container.
+ * It's return value of onDeviceAllocated invoked by the framework.
+ * For preparation, if volumeSpecs is populated then the framework will
+ * create the volume before using the device
+ * When running container, the envs indicates environment variable needed.
+ * The containerRuntime indicates what Docker runtime to use.
+ * The volume & device mounts describes key isolation requirements
+ * */
+public final class DeviceRuntimeSpec implements Serializable {
+
+ private static final long serialVersionUID = 554704120015467660L;
+
+ /**
+ * The containerRuntime gives device framework a hint (not forced to).
+ * On which containerRuntime be used
+ * (if empty then default "runc" is used).
+ * For instance, it could be "nvidia" in Nvidia GPU Docker v2.
+ * The "nvidia" will be passed as a parameter to docker run
+ * with --runtime "nvidia"
+ */
+ private final String containerRuntime;
+ private final Map<String, String> envs;
+ private final Set<MountVolumeSpec> volumeMounts;
+ private final Set<MountDeviceSpec> deviceMounts;
+ private final Set<VolumeSpec> volumeSpecs;
+
+ private DeviceRuntimeSpec(Builder builder) {
+ this.containerRuntime = builder.containerRuntime;
+ this.deviceMounts = builder.deviceMounts;
+ this.envs = builder.envs;
+ this.volumeSpecs = builder.volumeSpecs;
+ this.volumeMounts = builder.volumeMounts;
+ }
+
+ public String getContainerRuntime() {
+ return containerRuntime;
+ }
+
+ public Map<String, String> getEnvs() {
+ return envs;
+ }
+
+ public Set<MountVolumeSpec> getVolumeMounts() {
+ return volumeMounts;
+ }
+
+ public Set<MountDeviceSpec> getDeviceMounts() {
+ return deviceMounts;
+ }
+
+ public Set<VolumeSpec> getVolumeSpecs() {
+ return volumeSpecs;
+ }
+ /**
+ * Builder for DeviceRuntimeSpec.
+ * */
+ public final static class Builder {
+
+ private String containerRuntime;
+ private Map<String, String> envs;
+ private Set<MountVolumeSpec> volumeMounts;
+ private Set<MountDeviceSpec> deviceMounts;
+ private Set<VolumeSpec> volumeSpecs;
+
+ private Builder() {
+ containerRuntime = "";
+ envs = new HashMap<>();
+ volumeSpecs = new TreeSet<>();
+ deviceMounts = new TreeSet<>();
+ volumeMounts = new TreeSet<>();
+ }
+
+ public static Builder newInstance() {
+ return new Builder();
+ }
+
+ public DeviceRuntimeSpec build() {
+ return new DeviceRuntimeSpec(this);
+ }
+
+ public Builder setContainerRuntime(String cRuntime) {
+ this.containerRuntime = cRuntime;
+ return this;
+ }
+
+ public Builder addVolumeSpec(VolumeSpec spec) {
+ this.volumeSpecs.add(spec);
+ return this;
+ }
+
+ public Builder addMountVolumeSpec(MountVolumeSpec spec) {
+ this.volumeMounts.add(spec);
+ return this;
+ }
+
+ public Builder addMountDeviceSpec(MountDeviceSpec spec) {
+ this.deviceMounts.add(spec);
+ return this;
+ }
+
+ public Builder addEnv(String key, String value) {
+ this.envs.put(Objects.requireNonNull(key),
+ Objects.requireNonNull(value));
+ return this;
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/MountDeviceSpec.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/MountDeviceSpec.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/MountDeviceSpec.java
new file mode 100644
index 0000000..e4a88de
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/MountDeviceSpec.java
@@ -0,0 +1,131 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.yarn.server.nodemanager.api.deviceplugin;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * Describe one device mount.
+ * */
+public final class MountDeviceSpec implements Serializable, Comparable {
+
+ private static final long serialVersionUID = -160806358136943052L;
+
+ private final String devicePathInHost;
+ private final String devicePathInContainer;
+
+ // r for only read, rw can do read and write
+ private final String devicePermission;
+
+ public final static String RO = "r";
+ public final static String RW = "rw";
+
+ private MountDeviceSpec(Builder builder) {
+ this.devicePathInContainer = builder.devicePathInContainer;
+ this.devicePathInHost = builder.devicePathInHost;
+ this.devicePermission = builder.devicePermission;
+ }
+
+ public String getDevicePathInHost() {
+ return devicePathInHost;
+ }
+
+ public String getDevicePathInContainer() {
+ return devicePathInContainer;
+ }
+
+ public String getDevicePermission() {
+ return devicePermission;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()){
+ return false;
+ }
+ MountDeviceSpec other = (MountDeviceSpec) o;
+ return Objects.equals(devicePathInHost, other.getDevicePathInHost())
+ && Objects.equals(devicePathInContainer,
+ other.getDevicePathInContainer())
+ && Objects.equals(devicePermission, other.getDevicePermission());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(devicePathInContainer,
+ devicePathInHost, devicePermission);
+ }
+
+ @Override
+ public int compareTo(Object o) {
+ if (o == null || (!(o instanceof MountDeviceSpec))) {
+ return -1;
+ }
+ MountDeviceSpec other = (MountDeviceSpec) o;
+ int result = devicePathInContainer.compareTo(
+ other.getDevicePathInContainer());
+ if (0 != result) {
+ return result;
+ }
+ result = devicePathInHost.compareTo(other.getDevicePathInHost());
+ if (0 != result) {
+ return result;
+ }
+ return devicePermission.compareTo(other.getDevicePermission());
+ }
+
+ /**
+ * Builder for MountDeviceSpec.
+ * */
+ public final static class Builder {
+ private String devicePathInHost;
+ private String devicePathInContainer;
+ private String devicePermission;
+
+ private Builder() {}
+
+ public static Builder newInstance() {
+ return new Builder();
+ }
+
+ public MountDeviceSpec build() {
+ return new MountDeviceSpec(this);
+ }
+
+ public Builder setDevicePermission(String permission) {
+ this.devicePermission = permission;
+ return this;
+ }
+
+ public Builder setDevicePathInContainer(String pathInContainer) {
+ this.devicePathInContainer = pathInContainer;
+ return this;
+ }
+
+ public Builder setDevicePathInHost(String pathInHost) {
+ this.devicePathInHost = pathInHost;
+ return this;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/MountVolumeSpec.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/MountVolumeSpec.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/MountVolumeSpec.java
new file mode 100644
index 0000000..6f6b183
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/MountVolumeSpec.java
@@ -0,0 +1,118 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.yarn.server.nodemanager.api.deviceplugin;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * Describe one volume mount.
+ * */
+public final class MountVolumeSpec implements Serializable, Comparable {
+
+ private static final long serialVersionUID = 2479676805545997492L;
+
+ // host path or volume name
+ private final String hostPath;
+
+ // path in the container
+ private final String mountPath;
+
+ // if true, data in mountPath can only be read
+ // "-v hostPath:mountPath:ro"
+ private final Boolean isReadOnly;
+
+ public final static String READONLYOPTION = "ro";
+
+ private MountVolumeSpec(Builder builder) {
+ this.hostPath = builder.hostPath;
+ this.mountPath = builder.mountPath;
+ this.isReadOnly = builder.isReadOnly;
+ }
+
+ public String getHostPath() {
+ return hostPath;
+ }
+
+ public String getMountPath() {
+ return mountPath;
+ }
+
+ public Boolean getReadOnly() {
+ return isReadOnly;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()){
+ return false;
+ }
+ MountVolumeSpec other = (MountVolumeSpec) o;
+ return Objects.equals(hostPath, other.getHostPath())
+ && Objects.equals(mountPath, other.getMountPath())
+ && Objects.equals(isReadOnly, other.getReadOnly());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(hostPath, mountPath, isReadOnly);
+ }
+
+ @Override
+ public int compareTo(Object o) {
+ return 0;
+ }
+
+ /**
+ * Builder for MountVolumeSpec.
+ * */
+ public final static class Builder {
+ private String hostPath;
+ private String mountPath;
+ private Boolean isReadOnly;
+
+ private Builder() {}
+
+ public static Builder newInstance() {
+ return new Builder();
+ }
+
+ public MountVolumeSpec build() {
+ return new MountVolumeSpec(this);
+ }
+
+ public Builder setHostPath(String hPath) {
+ this.hostPath = hPath;
+ return this;
+ }
+
+ public Builder setMountPath(String mPath) {
+ this.mountPath = mPath;
+ return this;
+ }
+
+ public Builder setReadOnly(Boolean readOnly) {
+ isReadOnly = readOnly;
+ return this;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/VolumeSpec.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/VolumeSpec.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/VolumeSpec.java
new file mode 100644
index 0000000..0f06be7
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/VolumeSpec.java
@@ -0,0 +1,114 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.yarn.server.nodemanager.api.deviceplugin;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * Describe one volume creation or deletion.
+ * */
+public final class VolumeSpec implements Serializable, Comparable {
+
+ private static final long serialVersionUID = 3483619025106416736L;
+
+ private final String volumeDriver;
+ private final String volumeName;
+ private final String volumeOperation;
+
+ public final static String CREATE = "create";
+ public final static String DELETE = "delete";
+
+ private VolumeSpec(Builder builder) {
+ this.volumeDriver = builder.volumeDriver;
+ this.volumeName = builder.volumeName;
+ this.volumeOperation = builder.volumeOperation;
+ }
+
+ public String getVolumeDriver() {
+ return volumeDriver;
+ }
+
+ public String getVolumeName() {
+ return volumeName;
+ }
+
+ public String getVolumeOperation() {
+ return volumeOperation;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()){
+ return false;
+ }
+ VolumeSpec other = (VolumeSpec) o;
+ return Objects.equals(volumeDriver, other.getVolumeDriver())
+ && Objects.equals(volumeName, other.getVolumeName())
+ && Objects.equals(volumeOperation, other.getVolumeOperation());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(volumeDriver, volumeName, volumeOperation);
+ }
+
+ @Override
+ public int compareTo(Object o) {
+ return 0;
+ }
+
+ /**
+ * Builder for VolumeSpec.
+ * */
+ public final static class Builder {
+ private String volumeDriver;
+ private String volumeName;
+ private String volumeOperation;
+
+ private Builder(){}
+
+ public static Builder newInstance() {
+ return new Builder();
+ }
+
+ public VolumeSpec build() {
+ return new VolumeSpec(this);
+ }
+
+ public Builder setVolumeDriver(String volDriver) {
+ this.volumeDriver = volDriver;
+ return this;
+ }
+
+ public Builder setVolumeName(String volName) {
+ this.volumeName = volName;
+ return this;
+ }
+
+ public Builder setVolumeOperation(String volOperation) {
+ this.volumeOperation = volOperation;
+ return this;
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/YarnRuntimeType.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/YarnRuntimeType.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/YarnRuntimeType.java
new file mode 100644
index 0000000..e0eb9dd
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/YarnRuntimeType.java
@@ -0,0 +1,42 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.yarn.server.nodemanager.api.deviceplugin;
+
+
+/**
+ * YarnRuntime parameter enum for {@link DevicePlugin}.
+ * It's passed into {@code onDevicesAllocated}.
+ * Device plugin could populate {@link DeviceRuntimeSpec}
+ * based on which YARN container runtime will use.
+ * */
+public enum YarnRuntimeType {
+
+ RUNTIME_DEFAULT("default"),
+ RUNTIME_DOCKER("docker");
+
+ private final String name;
+
+ YarnRuntimeType(String n) {
+ this.name = n;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/package-info.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/package-info.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/package-info.java
new file mode 100644
index 0000000..fd7ef24
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/api/deviceplugin/package-info.java
@@ -0,0 +1,19 @@
+/**
+ * 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.hadoop.yarn.server.nodemanager.api.deviceplugin;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/ResourcePluginManager.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/ResourcePluginManager.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/ResourcePluginManager.java
index e930d96..9741b12 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/ResourcePluginManager.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/ResourcePluginManager.java
@@ -18,18 +18,26 @@
package org.apache.hadoop.yarn.server.nodemanager.containermanager.resourceplugin;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.util.ReflectionUtils;
+import org.apache.hadoop.yarn.api.records.ResourceInformation;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.exceptions.YarnException;
import org.apache.hadoop.yarn.exceptions.YarnRuntimeException;
import org.apache.hadoop.yarn.server.nodemanager.Context;
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.DevicePlugin;
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.DeviceRegisterRequest;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.deviceframework.DevicePluginAdapter;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.fpga.FpgaResourcePlugin;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.gpu.GpuResourcePlugin;
+import org.apache.hadoop.yarn.util.resource.ResourceUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -50,8 +58,9 @@ public class ResourcePluginManager {
private Map<String, ResourcePlugin> configuredPlugins =
Collections.emptyMap();
+
public synchronized void initialize(Context context)
- throws YarnException {
+ throws YarnException, ClassNotFoundException {
Configuration conf = context.getConf();
Map<String, ResourcePlugin> pluginMap = new HashMap<>();
@@ -111,7 +120,7 @@ public class ResourcePluginManager {
public void initializePluggableDevicePlugins(Context context,
Configuration configuration,
Map<String, ResourcePlugin> pluginMap)
- throws YarnRuntimeException {
+ throws YarnRuntimeException, ClassNotFoundException {
LOG.info("The pluggable device framework enabled," +
"trying to load the vendor plugins");
@@ -121,6 +130,109 @@ public class ResourcePluginManager {
throw new YarnRuntimeException("Null value found in configuration: "
+ YarnConfiguration.NM_PLUGGABLE_DEVICE_FRAMEWORK_DEVICE_CLASSES);
}
+
+ for (String pluginClassName : pluginClassNames) {
+ Class<?> pluginClazz = Class.forName(pluginClassName);
+ if (!DevicePlugin.class.isAssignableFrom(pluginClazz)) {
+ throw new YarnRuntimeException("Class: " + pluginClassName
+ + " not instance of " + DevicePlugin.class.getCanonicalName());
+ }
+ // sanity-check before initialization
+ checkInterfaceCompatibility(DevicePlugin.class, pluginClazz);
+
+ DevicePlugin dpInstance =
+ (DevicePlugin) ReflectionUtils.newInstance(
+ pluginClazz, configuration);
+
+ // Try to register plugin
+ // TODO: handle the plugin method timeout issue
+ DeviceRegisterRequest request = null;
+ try {
+ request = dpInstance.getRegisterRequestInfo();
+ } catch (Exception e) {
+ throw new YarnRuntimeException("Exception thrown from plugin's"
+ + " getRegisterRequestInfo:"
+ + e.getMessage());
+ }
+ String resourceName = request.getResourceName();
+ // check if someone has already registered this resource type name
+ if (pluginMap.containsKey(resourceName)) {
+ throw new YarnRuntimeException(resourceName
+ + " already registered! Please change resource type name"
+ + " or configure correct resource type name"
+ + " in resource-types.xml for "
+ + pluginClassName);
+ }
+ // check resource name is valid and configured in resource-types.xml
+ if (!isConfiguredResourceName(resourceName)) {
+ throw new YarnRuntimeException(resourceName
+ + " is not configured inside "
+ + YarnConfiguration.RESOURCE_TYPES_CONFIGURATION_FILE
+ + " , please configure it first");
+ }
+ LOG.info("New resource type: {} registered successfully by {}",
+ resourceName,
+ pluginClassName);
+ DevicePluginAdapter pluginAdapter = new DevicePluginAdapter(
+ resourceName, dpInstance);
+ LOG.info("Adapter of {} created. Initializing..", pluginClassName);
+ try {
+ pluginAdapter.initialize(context);
+ } catch (YarnException e) {
+ throw new YarnRuntimeException("Adapter of "
+ + pluginClassName + " init failed!");
+ }
+ LOG.info("Adapter of {} init success!", pluginClassName);
+ // Store plugin as adapter instance
+ pluginMap.put(request.getResourceName(), pluginAdapter);
+ } // end for
+ }
+
+ @VisibleForTesting
+ // Check if the implemented interfaces' signature is compatible
+ public void checkInterfaceCompatibility(Class<?> expectedClass,
+ Class<?> actualClass) throws YarnRuntimeException{
+ LOG.debug("Checking implemented interface's compatibility: {}",
+ expectedClass.getSimpleName());
+ Method[] expectedDevicePluginMethods = expectedClass.getMethods();
+
+ // Check method compatibility
+ boolean found;
+ for (Method method: expectedDevicePluginMethods) {
+ found = false;
+ LOG.debug("Try to find method: {}",
+ method.getName());
+ for (Method m : actualClass.getDeclaredMethods()) {
+ if (m.getName().equals(method.getName())) {
+ LOG.debug("Method {} found in class {}",
+ actualClass.getSimpleName(),
+ m.getName());
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ LOG.error("Method {} is not found in plugin",
+ method.getName());
+ throw new YarnRuntimeException(
+ "Method " + method.getName()
+ + " is expected but not implemented in "
+ + actualClass.getCanonicalName());
+ }
+ }// end for
+ LOG.info("{} compatibility is ok.",
+ expectedClass.getSimpleName());
+ }
+
+ @VisibleForTesting
+ public boolean isConfiguredResourceName(String resourceName) {
+ // check configured
+ Map<String, ResourceInformation> configuredResourceTypes =
+ ResourceUtils.getResourceTypes();
+ if (!configuredResourceTypes.containsKey(resourceName)) {
+ return false;
+ }
+ return true;
}
public synchronized void cleanup() throws YarnException {
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/DevicePluginAdapter.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/DevicePluginAdapter.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/DevicePluginAdapter.java
new file mode 100644
index 0000000..18a6992
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/DevicePluginAdapter.java
@@ -0,0 +1,88 @@
+/**
+ * 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.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.deviceframework;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.server.nodemanager.Context;
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.DevicePlugin;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperationExecutor;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.CGroupsHandler;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.ResourceHandler;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.DockerCommandPlugin;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.NodeResourceUpdaterPlugin;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.ResourcePlugin;
+import org.apache.hadoop.yarn.server.nodemanager.webapp.dao.NMResourceInfo;
+
+
+/**
+ * The {@link DevicePluginAdapter} will adapt existing hooks
+ * into vendor plugin's logic.
+ * It decouples the vendor plugin from YARN's device framework
+ *
+ * */
+public class DevicePluginAdapter implements ResourcePlugin {
+ private final static Log LOG = LogFactory.getLog(DevicePluginAdapter.class);
+
+ private final String resourceName;
+ private final DevicePlugin devicePlugin;
+ private DeviceResourceUpdaterImpl deviceResourceUpdater;
+
+ public DevicePluginAdapter(String name, DevicePlugin dp) {
+ resourceName = name;
+ devicePlugin = dp;
+ }
+
+ @Override
+ public void initialize(Context context) throws YarnException {
+ deviceResourceUpdater = new DeviceResourceUpdaterImpl(
+ resourceName, devicePlugin);
+ LOG.info(resourceName + " plugin adapter initialized");
+ return;
+ }
+
+ @Override
+ public ResourceHandler createResourceHandler(Context nmContext,
+ CGroupsHandler cGroupsHandler,
+ PrivilegedOperationExecutor privilegedOperationExecutor) {
+ return null;
+ }
+
+ @Override
+ public NodeResourceUpdaterPlugin getNodeResourceHandlerInstance() {
+ return deviceResourceUpdater;
+ }
+
+ @Override
+ public void cleanup() {
+
+ }
+
+ @Override
+ public DockerCommandPlugin getDockerCommandPluginInstance() {
+ return null;
+ }
+
+ @Override
+ public NMResourceInfo getNMResourceInfo() throws YarnException {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/DeviceResourceUpdaterImpl.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/DeviceResourceUpdaterImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/DeviceResourceUpdaterImpl.java
new file mode 100644
index 0000000..e5ef578
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/DeviceResourceUpdaterImpl.java
@@ -0,0 +1,66 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.deviceframework;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.yarn.api.records.Resource;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.Device;
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.DevicePlugin;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.NodeResourceUpdaterPlugin;
+
+import java.util.Set;
+
+/**
+ * Hooks into NodeStatusUpdater to update resource.
+ * */
+public class DeviceResourceUpdaterImpl extends NodeResourceUpdaterPlugin {
+
+ final static Log LOG = LogFactory.getLog(DeviceResourceUpdaterImpl.class);
+
+ private String resourceName;
+ private DevicePlugin devicePlugin;
+
+ public DeviceResourceUpdaterImpl(String resourceName,
+ DevicePlugin devicePlugin) {
+ this.devicePlugin = devicePlugin;
+ this.resourceName = resourceName;
+ }
+
+ @Override
+ public void updateConfiguredResource(Resource res)
+ throws YarnException {
+ LOG.info(resourceName + " plugin update resource ");
+ Set<Device> devices = null;
+ try {
+ devices = devicePlugin.getDevices();
+ } catch (Exception e) {
+ throw new YarnException("Exception thrown from plugin's getDevices"
+ + e.getMessage());
+ }
+ if (null == devices) {
+ LOG.warn(resourceName
+ + " plugin failed to discover resource ( null value got).");
+ return;
+ }
+ res.setResourceValue(resourceName, devices.size());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/package-info.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/package-info.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/package-info.java
new file mode 100644
index 0000000..c64fa95
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/package-info.java
@@ -0,0 +1,19 @@
+/**
+ * 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.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.deviceframework;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/package-info.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/package-info.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/package-info.java
new file mode 100644
index 0000000..b4be249
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/package-info.java
@@ -0,0 +1,19 @@
+/**
+ * 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.hadoop.yarn.server.nodemanager.containermanager.resourceplugin;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/TestResourcePluginManager.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/TestResourcePluginManager.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/TestResourcePluginManager.java
index eb8bf54..f623375 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/TestResourcePluginManager.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/TestResourcePluginManager.java
@@ -34,6 +34,7 @@ import org.apache.hadoop.yarn.server.nodemanager.NodeHealthCheckerService;
import org.apache.hadoop.yarn.server.nodemanager.NodeManager;
import org.apache.hadoop.yarn.server.nodemanager.NodeManagerTestBase;
import org.apache.hadoop.yarn.server.nodemanager.NodeStatusUpdater;
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.DevicePlugin;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.ContainerManagerImpl;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperation;
@@ -42,7 +43,10 @@ import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resource
import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.ResourceHandler;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.ResourceHandlerChain;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.ResourceHandlerException;
+import org.apache.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.deviceframework.*;
import org.apache.hadoop.yarn.server.security.ApplicationACLsManager;
+import org.apache.hadoop.yarn.util.resource.ResourceUtils;
+import org.apache.hadoop.yarn.util.resource.TestResourceUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -51,6 +55,7 @@ import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.io.File;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
@@ -64,9 +69,16 @@ public class TestResourcePluginManager extends NodeManagerTestBase {
private YarnConfiguration conf;
+ private String tempResourceTypesFile;
+
@Before
public void setup() throws Exception {
this.conf = createNMConfig();
+ // setup resource-types.xml
+ ResourceUtils.resetResourceTypes();
+ String resourceTypesFile = "resource-types-pluggable-devices.xml";
+ this.tempResourceTypesFile =
+ TestResourceUtils.setupResourceTypes(this.conf, resourceTypesFile);
}
ResourcePluginManager stubResourcePluginmanager() {
@@ -101,6 +113,11 @@ public class TestResourcePluginManager extends NodeManagerTestBase {
// ignore
}
}
+ // cleanup resource-types.xml
+ File dest = new File(this.tempResourceTypesFile);
+ if (dest.exists()) {
+ dest.delete();
+ }
}
private class CustomizedResourceHandler implements ResourceHandler {
@@ -153,8 +170,8 @@ public class TestResourcePluginManager extends NodeManagerTestBase {
protected NodeStatusUpdater createNodeStatusUpdater(Context context,
Dispatcher dispatcher, NodeHealthCheckerService healthChecker) {
((NodeManager.NMContext)context).setResourcePluginManager(rpm);
- return new BaseNodeStatusUpdaterForTest(context, dispatcher, healthChecker,
- metrics, new BaseResourceTrackerForTest());
+ return new BaseNodeStatusUpdaterForTest(context, dispatcher,
+ healthChecker, metrics, new BaseResourceTrackerForTest());
}
@Override
@@ -174,7 +191,8 @@ public class TestResourcePluginManager extends NodeManagerTestBase {
}
public class MyLCE extends LinuxContainerExecutor {
- private PrivilegedOperationExecutor poe = mock(PrivilegedOperationExecutor.class);
+ private PrivilegedOperationExecutor poe =
+ mock(PrivilegedOperationExecutor.class);
@Override
protected PrivilegedOperationExecutor getPrivilegedOperationExecutor() {
@@ -199,7 +217,8 @@ public class TestResourcePluginManager extends NodeManagerTestBase {
* Make sure ResourcePluginManager is invoked during NM update.
*/
@Test(timeout = 30000)
- public void testNodeStatusUpdaterWithResourcePluginsEnabled() throws Exception {
+ public void testNodeStatusUpdaterWithResourcePluginsEnabled()
+ throws Exception {
final ResourcePluginManager rpm = stubResourcePluginmanager();
nm = new MyMockNM(rpm);
@@ -211,15 +230,16 @@ public class TestResourcePluginManager extends NodeManagerTestBase {
rpm.getNameToPlugins().get("resource1")
.getNodeResourceHandlerInstance();
- verify(nodeResourceUpdaterPlugin, times(1)).updateConfiguredResource(
- any(Resource.class));
+ verify(nodeResourceUpdaterPlugin, times(1))
+ .updateConfiguredResource(any(Resource.class));
}
/*
* Make sure ResourcePluginManager is used to initialize ResourceHandlerChain
*/
@Test(timeout = 30000)
- public void testLinuxContainerExecutorWithResourcePluginsEnabled() throws Exception {
+ public void testLinuxContainerExecutorWithResourcePluginsEnabled()
+ throws Exception {
final ResourcePluginManager rpm = stubResourcePluginmanager();
final LinuxContainerExecutor lce = new MyLCE();
@@ -261,6 +281,9 @@ public class TestResourcePluginManager extends NodeManagerTestBase {
boolean newHandlerAdded = false;
for (ResourceHandler h : ((ResourceHandlerChain) handler)
.getResourceHandlerList()) {
+ if (h instanceof DevicePluginAdapter) {
+ Assert.assertTrue(false);
+ }
if (h instanceof CustomizedResourceHandler) {
newHandlerAdded = true;
break;
@@ -320,7 +343,7 @@ public class TestResourcePluginManager extends NodeManagerTestBase {
true);
conf.setStrings(
YarnConfiguration.NM_PLUGGABLE_DEVICE_FRAMEWORK_DEVICE_CLASSES,
- "com.cmp1.hdw1plugin");
+ FakeTestDevicePlugin1.class.getCanonicalName());
nm.init(conf);
nm.start();
verify(rpmSpy, times(1)).initialize(
@@ -332,7 +355,8 @@ public class TestResourcePluginManager extends NodeManagerTestBase {
// Enable pluggable framework, but leave device classes un-configured
// initializePluggableDevicePlugins invoked but it should throw an exception
@Test(timeout = 30000)
- public void testInitializationWithPluggableDeviceFrameworkEnabled2() {
+ public void testInitializationWithPluggableDeviceFrameworkEnabled2()
+ throws ClassNotFoundException {
ResourcePluginManager rpm = new ResourcePluginManager();
ResourcePluginManager rpmSpy = spy(rpm);
@@ -353,4 +377,131 @@ public class TestResourcePluginManager extends NodeManagerTestBase {
any(Context.class), any(Configuration.class), any(Map.class));
Assert.assertTrue(fail);
}
+
+ @Test(timeout = 30000)
+ public void testNormalInitializationOfPluggableDeviceClasses()
+ throws Exception {
+
+ ResourcePluginManager rpm = new ResourcePluginManager();
+
+ ResourcePluginManager rpmSpy = spy(rpm);
+ nm = new MyMockNM(rpmSpy);
+
+ conf.setBoolean(YarnConfiguration.NM_PLUGGABLE_DEVICE_FRAMEWORK_ENABLED,
+ true);
+ conf.setStrings(
+ YarnConfiguration.NM_PLUGGABLE_DEVICE_FRAMEWORK_DEVICE_CLASSES,
+ FakeTestDevicePlugin1.class.getCanonicalName());
+ nm.init(conf);
+ nm.start();
+ Map<String, ResourcePlugin> pluginMap = rpmSpy.getNameToPlugins();
+ Assert.assertEquals(1, pluginMap.size());
+ ResourcePlugin rp = pluginMap.get("cmpA.com/hdwA");
+ if (!(rp instanceof DevicePluginAdapter)) {
+ Assert.assertTrue(false);
+ }
+ verify(rpmSpy, times(1)).checkInterfaceCompatibility(
+ DevicePlugin.class, FakeTestDevicePlugin1.class);
+ }
+
+ // Fail to load a class which doesn't implement interface DevicePlugin
+ @Test(timeout = 30000)
+ public void testLoadInvalidPluggableDeviceClasses()
+ throws Exception{
+ ResourcePluginManager rpm = new ResourcePluginManager();
+
+ ResourcePluginManager rpmSpy = spy(rpm);
+ nm = new MyMockNM(rpmSpy);
+
+ conf.setBoolean(YarnConfiguration.NM_PLUGGABLE_DEVICE_FRAMEWORK_ENABLED,
+ true);
+ conf.setStrings(
+ YarnConfiguration.NM_PLUGGABLE_DEVICE_FRAMEWORK_DEVICE_CLASSES,
+ FakeTestDevicePlugin2.class.getCanonicalName());
+
+ String expectedMessage = "Class: "
+ + FakeTestDevicePlugin2.class.getCanonicalName()
+ + " not instance of " + DevicePlugin.class.getCanonicalName();
+ String actualMessage = "";
+ try {
+ nm.init(conf);
+ nm.start();
+ } catch (YarnRuntimeException e) {
+ actualMessage = e.getMessage();
+ }
+ Assert.assertEquals(expectedMessage, actualMessage);
+ }
+
+ // Fail to register duplicated resource name.
+ @Test(timeout = 30000)
+ public void testLoadDuplicateResourceNameDevicePlugin()
+ throws Exception{
+ ResourcePluginManager rpm = new ResourcePluginManager();
+
+ ResourcePluginManager rpmSpy = spy(rpm);
+ nm = new MyMockNM(rpmSpy);
+
+ conf.setBoolean(YarnConfiguration.NM_PLUGGABLE_DEVICE_FRAMEWORK_ENABLED,
+ true);
+ conf.setStrings(
+ YarnConfiguration.NM_PLUGGABLE_DEVICE_FRAMEWORK_DEVICE_CLASSES,
+ FakeTestDevicePlugin1.class.getCanonicalName() + "," +
+ FakeTestDevicePlugin3.class.getCanonicalName());
+
+ String expectedMessage = "cmpA.com/hdwA" +
+ " already registered! Please change resource type name"
+ + " or configure correct resource type name"
+ + " in resource-types.xml for "
+ + FakeTestDevicePlugin3.class.getCanonicalName();
+ String actualMessage = "";
+ try {
+ nm.init(conf);
+ nm.start();
+ } catch (YarnRuntimeException e) {
+ actualMessage = e.getMessage();
+ }
+ Assert.assertEquals(expectedMessage, actualMessage);
+ }
+
+ /**
+ * Fail a plugin due to incompatible interface implemented.
+ * It doesn't implement the "getRegisterRequestInfo"
+ */
+ @Test(timeout = 30000)
+ public void testIncompatibleDevicePlugin()
+ throws Exception {
+ ResourcePluginManager rpm = new ResourcePluginManager();
+
+ ResourcePluginManager rpmSpy = spy(rpm);
+ nm = new MyMockNM(rpmSpy);
+
+ conf.setBoolean(YarnConfiguration.NM_PLUGGABLE_DEVICE_FRAMEWORK_ENABLED,
+ true);
+ conf.setStrings(
+ YarnConfiguration.NM_PLUGGABLE_DEVICE_FRAMEWORK_DEVICE_CLASSES,
+ FakeTestDevicePlugin4.class.getCanonicalName());
+
+ String expectedMessage = "Method getRegisterRequestInfo" +
+ " is expected but not implemented in "
+ + FakeTestDevicePlugin4.class.getCanonicalName();
+ String actualMessage = "";
+ try {
+ nm.init(conf);
+ nm.start();
+ } catch (YarnRuntimeException e) {
+ actualMessage = e.getMessage();
+ }
+ Assert.assertEquals(expectedMessage, actualMessage);
+ }
+
+ @Test(timeout = 30000)
+ public void testRequestedResourceNameIsConfigured()
+ throws Exception{
+ ResourcePluginManager rpm = new ResourcePluginManager();
+ String resourceName = "a.com/a";
+ Assert.assertFalse(rpm.isConfiguredResourceName(resourceName));
+ resourceName = "cmp.com/cmp";
+ Assert.assertTrue(rpm.isConfiguredResourceName(resourceName));
+ }
+
}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/FakeTestDevicePlugin1.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/FakeTestDevicePlugin1.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/FakeTestDevicePlugin1.java
new file mode 100644
index 0000000..d708c87
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/FakeTestDevicePlugin1.java
@@ -0,0 +1,61 @@
+/**
+ * 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.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.deviceframework;
+
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.*;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * Used only for testing.
+ * A fake normal vendor plugin
+ * */
+public class FakeTestDevicePlugin1 implements DevicePlugin {
+ @Override
+ public DeviceRegisterRequest getRegisterRequestInfo() {
+ return DeviceRegisterRequest.Builder.newInstance()
+ .setResourceName("cmpA.com/hdwA").build();
+ }
+
+ @Override
+ public Set<Device> getDevices() {
+ TreeSet<Device> r = new TreeSet<>();
+ r.add(Device.Builder.newInstance()
+ .setId(0)
+ .setDevPath("/dev/hdwA0")
+ .setMajorNumber(243)
+ .setMinorNumber(0)
+ .setBusID("0000:65:00.0")
+ .setHealthy(true)
+ .build());
+ return r;
+ }
+
+ @Override
+ public DeviceRuntimeSpec onDevicesAllocated(Set<Device> allocatedDevices,
+ YarnRuntimeType yarnRuntime) throws Exception {
+ return null;
+ }
+
+ @Override
+ public void onDevicesReleased(Set<Device> allocatedDevices) {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/FakeTestDevicePlugin2.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/FakeTestDevicePlugin2.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/FakeTestDevicePlugin2.java
new file mode 100644
index 0000000..8c1a61d
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/FakeTestDevicePlugin2.java
@@ -0,0 +1,27 @@
+/**
+ * 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.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.deviceframework;
+
+/**
+ * Only used for testing.
+ * This isn't a implementation of DevicePlugin
+ * */
+public class FakeTestDevicePlugin2 {
+
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/FakeTestDevicePlugin3.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/FakeTestDevicePlugin3.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/FakeTestDevicePlugin3.java
new file mode 100644
index 0000000..67bf8db
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/FakeTestDevicePlugin3.java
@@ -0,0 +1,65 @@
+/**
+ * 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.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.deviceframework;
+
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.Device;
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.DevicePlugin;
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.DeviceRegisterRequest;
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.DeviceRuntimeSpec;
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.YarnRuntimeType;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * Only used for testing.
+ * This plugin register a same name with FakeTestDevicePlugin1
+ * */
+public class FakeTestDevicePlugin3 implements DevicePlugin {
+ @Override
+ public DeviceRegisterRequest getRegisterRequestInfo() {
+ return DeviceRegisterRequest.Builder.newInstance()
+ .setResourceName("cmpA.com/hdwA").build();
+ }
+
+ @Override
+ public Set<Device> getDevices() {
+ TreeSet<Device> r = new TreeSet<>();
+ r.add(Device.Builder.newInstance()
+ .setId(0)
+ .setDevPath("/dev/hdwA0")
+ .setMajorNumber(243)
+ .setMinorNumber(0)
+ .setBusID("0000:65:00.0")
+ .setHealthy(true)
+ .build());
+ return r;
+ }
+
+ @Override
+ public DeviceRuntimeSpec onDevicesAllocated(Set<Device> allocatedDevices,
+ YarnRuntimeType yarnRuntime) throws Exception {
+ return null;
+ }
+
+ @Override
+ public void onDevicesReleased(Set<Device> allocatedDevices) {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/FakeTestDevicePlugin4.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/FakeTestDevicePlugin4.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/FakeTestDevicePlugin4.java
new file mode 100644
index 0000000..445994d
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/FakeTestDevicePlugin4.java
@@ -0,0 +1,54 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.deviceframework;
+
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.Device;
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.DevicePlugin;
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.DeviceRegisterRequest;
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.DeviceRuntimeSpec;
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.YarnRuntimeType;
+
+import java.util.Set;
+
+/**
+ * Implement the interface but missed getRegisterRequestInfo method.
+ * This is equivalent to implements a old version of DevicePlugin
+ */
+public abstract class FakeTestDevicePlugin4 implements DevicePlugin {
+
+ public DeviceRegisterRequest getOldRegisterRequestInfo() {
+ return null;
+ }
+
+ @Override
+ public Set<Device> getDevices() {
+ return null;
+ }
+
+ @Override
+ public DeviceRuntimeSpec onDevicesAllocated(Set<Device> allocatedDevices,
+ YarnRuntimeType yarnRuntime) throws Exception {
+ return null;
+ }
+
+ @Override
+ public void onDevicesReleased(Set<Device> releasedDevices) {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/TestDevicePluginAdapter.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/TestDevicePluginAdapter.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/TestDevicePluginAdapter.java
new file mode 100644
index 0000000..c938b83
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/resourceplugin/deviceframework/TestDevicePluginAdapter.java
@@ -0,0 +1,145 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.yarn.server.nodemanager.containermanager.resourceplugin.deviceframework;
+
+import org.apache.hadoop.yarn.api.records.*;
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
+import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.server.nodemanager.*;
+import org.apache.hadoop.yarn.server.nodemanager.api.deviceplugin.*;
+import org.apache.hadoop.yarn.util.resource.ResourceUtils;
+import org.apache.hadoop.yarn.util.resource.TestResourceUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+import java.util.TreeSet;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.times;
+
+/**
+ * Unit tests for DevicePluginAdapter.
+ * About interaction with vendor plugin
+ * */
+public class TestDevicePluginAdapter {
+
+ protected static final Logger LOG =
+ LoggerFactory.getLogger(TestDevicePluginAdapter.class);
+
+ private YarnConfiguration conf;
+ private String tempResourceTypesFile;
+
+ @Before
+ public void setup() throws Exception {
+ this.conf = new YarnConfiguration();
+ // setup resource-types.xml
+ ResourceUtils.resetResourceTypes();
+ String resourceTypesFile = "resource-types-pluggable-devices.xml";
+ this.tempResourceTypesFile =
+ TestResourceUtils.setupResourceTypes(this.conf, resourceTypesFile);
+ }
+
+ @After
+ public void tearDown() throws IOException {
+ // cleanup resource-types.xml
+ File dest = new File(this.tempResourceTypesFile);
+ if (dest.exists()) {
+ dest.delete();
+ }
+ }
+
+ @Test
+ public void testDeviceResourceUpdaterImpl() throws YarnException {
+ Resource nodeResource = mock(Resource.class);
+ // Init an plugin
+ MyPlugin plugin = new MyPlugin();
+ MyPlugin spyPlugin = spy(plugin);
+ String resourceName = MyPlugin.RESOURCE_NAME;
+ // Init an adapter for the plugin
+ DevicePluginAdapter adapter = new DevicePluginAdapter(
+ resourceName,
+ spyPlugin);
+ adapter.initialize(mock(Context.class));
+ adapter.getNodeResourceHandlerInstance()
+ .updateConfiguredResource(nodeResource);
+ verify(spyPlugin, times(1)).getDevices();
+ verify(nodeResource, times(1)).setResourceValue(
+ resourceName, 3);
+ }
+
+ private class MyPlugin implements DevicePlugin {
+ private final static String RESOURCE_NAME = "cmpA.com/hdwA";
+ @Override
+ public DeviceRegisterRequest getRegisterRequestInfo() {
+ return DeviceRegisterRequest.Builder.newInstance()
+ .setResourceName(RESOURCE_NAME)
+ .setPluginVersion("v1.0").build();
+ }
+
+ @Override
+ public Set<Device> getDevices() {
+ TreeSet<Device> r = new TreeSet<>();
+ r.add(Device.Builder.newInstance()
+ .setId(0)
+ .setDevPath("/dev/hdwA0")
+ .setMajorNumber(256)
+ .setMinorNumber(0)
+ .setBusID("0000:80:00.0")
+ .setHealthy(true)
+ .build());
+ r.add(Device.Builder.newInstance()
+ .setId(1)
+ .setDevPath("/dev/hdwA1")
+ .setMajorNumber(256)
+ .setMinorNumber(0)
+ .setBusID("0000:80:01.0")
+ .setHealthy(true)
+ .build());
+ r.add(Device.Builder.newInstance()
+ .setId(2)
+ .setDevPath("/dev/hdwA2")
+ .setMajorNumber(256)
+ .setMinorNumber(0)
+ .setBusID("0000:80:02.0")
+ .setHealthy(true)
+ .build());
+ return r;
+ }
+
+ @Override
+ public DeviceRuntimeSpec onDevicesAllocated(Set<Device> allocatedDevices,
+ YarnRuntimeType yarnRuntime) throws Exception {
+ return null;
+ }
+
+ @Override
+ public void onDevicesReleased(Set<Device> releasedDevices) {
+
+ }
+ } // MyPlugin
+
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/63578036/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/resources/resource-types-pluggable-devices.xml
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/resources/resource-types-pluggable-devices.xml b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/resources/resource-types-pluggable-devices.xml
new file mode 100644
index 0000000..42d3278
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/resources/resource-types-pluggable-devices.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<!--
+ Licensed 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. See accompanying LICENSE file.
+-->
+
+<configuration>
+
+ <property>
+ <name>yarn.resource-types</name>
+ <value>cmp.com/cmp,cmpA.com/hdwA</value>
+ </property>
+</configuration>
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org