commit 5a922b7ee99e1277c55466b8ac2bd52f761c77e5 Author: Eric Yang Date: Mon Mar 4 17:35:14 2019 -0500 YARN-9292. Enhance YARN Service AM to use image ID to keep image tag "latest" consistent across nodes. Contributed by Eric Yang diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/ServiceScheduler.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/ServiceScheduler.java index 458a7a1..abffbda 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/ServiceScheduler.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/ServiceScheduler.java @@ -66,6 +66,7 @@ import org.apache.hadoop.yarn.service.api.records.ContainerState; import org.apache.hadoop.yarn.service.api.records.Service; import org.apache.hadoop.yarn.service.api.records.ServiceState; +import org.apache.hadoop.yarn.service.api.records.Artifact.TypeEnum; import org.apache.hadoop.yarn.service.api.records.ConfigFile; import org.apache.hadoop.yarn.service.component.ComponentRestartPolicy; import org.apache.hadoop.yarn.service.component.instance.ComponentInstance; @@ -93,6 +94,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.URI; import java.net.URISyntaxException; @@ -602,6 +604,15 @@ private void createAllComponents() { ServiceApiUtil.sortByDependencies(app.getComponents()); for (org.apache.hadoop.yarn.service.api.records.Component compSpec : sortedComponents) { + if (compSpec.getArtifact()!=null && compSpec.getArtifact().getType()==TypeEnum.DOCKER) { + String id = compSpec.getArtifact().getId(); + if (id!=null && id.endsWith("latest")) { + // Lookup image id for service to remain uniform + String imageId = getImageId(id); + LOG.info("Docker image: " + id + " maps to: " + imageId); + compSpec.getArtifact().setId(imageId); + } + } Component component = new Component(compSpec, allocateId, context); componentsById.put(allocateId, component); componentsByName.put(component.getName(), component); @@ -1141,4 +1152,37 @@ public void syncSysFs(Service yarnApp) { LOG.error("Fail to sync service spec: {}", e); } } + + private String getImageId(String name) { + Configuration conf = getConfig(); + String port = conf.get("yarn.nodemanager.webapp.address").split(":")[1]; + boolean useKerberos = UserGroupInformation.isSecurityEnabled(); + StringBuilder requestPath = new StringBuilder(); + if (YarnConfiguration.useHttps(conf)) { + requestPath.append("https://"); + } else { + requestPath.append("http://"); + } + try { + InetAddress inetAddress = InetAddress. getLocalHost(); + String node = inetAddress.getHostName(); + requestPath.append(node) + .append(":") + .append(port) + .append("/ws/v1/node/docker/images/") + .append(name); + if (!useKerberos) { + requestPath.append("?user.name=") + .append(UserGroupInformation.getCurrentUser() + .getShortUserName()); + } + Builder builder = HttpUtil.connect(requestPath.toString()); + String imageId = "@" + builder.get(String.class); + String digestId = name.replace(":latest", imageId); + return digestId; + } catch (IOException | URISyntaxException | InterruptedException e) { + LOG.warn("Unable to resolve " + name + " to image id, error: {}", e); + } + return name; + } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/NMWebServices.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/NMWebServices.java index 106144f..391fd85 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/NMWebServices.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/NMWebServices.java @@ -80,6 +80,8 @@ import org.apache.hadoop.yarn.server.nodemanager.containermanager.application.ApplicationState; import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container; import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerState; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker.DockerCommandExecutor; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker.DockerImagesCommand; import org.apache.hadoop.yarn.server.nodemanager.webapp.dao.AppInfo; import org.apache.hadoop.yarn.server.nodemanager.webapp.dao.AppsInfo; import org.apache.hadoop.yarn.server.nodemanager.webapp.dao.ContainerInfo; @@ -706,4 +708,17 @@ private UserGroupInformation getCallerUserGroupInformation( return callerUGI; } + + @GET + @Path("/docker/images/{name}") + @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8, + MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 }) + public String getImageId(@PathParam("name") String name) { + DockerImagesCommand dockerImagesCommand = new DockerImagesCommand(); + dockerImagesCommand = dockerImagesCommand.getSingleImageStatus(name); + // TODO: Add logic for privilegedOperation from YARN-9249 + // DockerCommandExecutor.executeDockerCommand(dockerImagesCommand, + // containerId, env, privilegedOperationExecutor, false, nmContext); + return "latest"; + } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/webapp/TestNMWebServices.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/webapp/TestNMWebServices.java index dbd980b..9d513e0 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/webapp/TestNMWebServices.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/webapp/TestNMWebServices.java @@ -838,4 +838,16 @@ private static String getRedirectURL(String url) { } return redirectUrl; } + + @Test + public void testGetImageId() { + WebResource r = resource(); + String expected = "latest"; + + // Access resource-1 should success + String id = r.path("ws").path("v1").path("node").path( + "docker").path("images").path("centos:latest").accept(MediaType.APPLICATION_JSON).get( + String.class); + assertEquals(expected, id); + } } \ No newline at end of file