AMBARI-19031: UI Enhancements, import/export assets and smart version configuration (Padma Priya via nitirajrathore)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/fb567758 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/fb567758 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/fb567758 Branch: refs/heads/trunk Commit: fb567758d71a4b90afa95d180f8340f6217f4f47 Parents: 8fc0ac7 Author: Nitiraj Rathore <[email protected]> Authored: Fri Dec 16 15:03:57 2016 +0530 Committer: Nitiraj Rathore <[email protected]> Committed: Fri Dec 16 15:03:57 2016 +0530 ---------------------------------------------------------------------- contrib/views/wfmanager/pom.xml | 29 +- .../apache/oozie/ambari/view/AmbariIOUtil.java | 65 +++ .../apache/oozie/ambari/view/HDFSFileUtils.java | 46 +- .../ambari/view/OozieProxyImpersonator.java | 236 +++++++--- .../apache/oozie/ambari/view/OozieUtils.java | 52 +++ .../oozie/ambari/view/WorkflowFileInfo.java | 64 +++ .../oozie/ambari/view/WorkflowFilesService.java | 116 +++++ .../oozie/ambari/view/assets/AssetRepo.java | 42 ++ .../oozie/ambari/view/assets/AssetService.java | 51 +++ .../ambari/view/assets/model/ActionAsset.java | 60 +++ .../oozie/ambari/view/model/BaseModel.java | 48 ++ .../workflowmanager/WorkflowManagerService.java | 76 ++++ .../WorkflowsManagerResource.java | 51 +++ .../view/workflowmanager/WorkflowsRepo.java | 69 +++ .../view/workflowmanager/model/Workflow.java | 88 ++++ .../ui/app/components/bundle-config.js | 18 +- .../ui/app/components/bundle-coord-config.js | 2 +- .../app/components/bundle-version-settings.js | 49 +++ .../resources/ui/app/components/coord-config.js | 30 +- .../ui/app/components/coord-version-settings.js | 49 +++ .../ui/app/components/date-with-expr.js | 1 - .../ui/app/components/designer-workspace.js | 63 ++- .../ui/app/components/flow-designer.js | 433 +++++++++++++++++-- .../resources/ui/app/components/hdfs-browser.js | 3 +- .../ui/app/components/import-from-stream.js | 67 +++ .../resources/ui/app/components/job-config.js | 2 +- .../resources/ui/app/components/job-details.js | 28 +- .../main/resources/ui/app/components/job-row.js | 4 + .../ui/app/components/name-value-config.js | 1 - .../ui/app/components/preview-dialog.js | 7 + .../main/resources/ui/app/components/save-wf.js | 49 +-- .../ui/app/components/search-create-new-bar.js | 17 +- .../ui/app/components/workflow-actions.js | 8 + .../ui/app/components/workflow-icon.js | 21 + .../ui/app/controllers/design/dashboardtab.js | 81 ++++ .../ui/app/controllers/design/jobtab.js | 59 +++ .../main/resources/ui/app/controllers/job.js | 30 +- .../app/domain/bundle/bundle-xml-generator.js | 2 +- .../ui/app/domain/bundle/bundle-xml-importer.js | 20 +- .../coordinator/coordinator-xml-generator.js | 2 +- .../coordinator/coordinator-xml-importer.js | 22 +- .../ui/app/domain/cytoscape-flow-renderer.js | 13 +- .../resources/ui/app/domain/mapping-utils.js | 2 +- .../resources/ui/app/domain/schema-versions.js | 165 ++++++- .../ui/app/domain/workflow-importer.js | 35 +- .../ui/app/domain/workflow-xml-generator.js | 15 + .../src/main/resources/ui/app/router.js | 5 +- .../main/resources/ui/app/routes/dashboard.js | 4 +- .../src/main/resources/ui/app/routes/design.js | 15 +- .../ui/app/routes/design/dashboardtab.js | 154 +++++++ .../resources/ui/app/routes/design/jobtab.js | 94 ++++ .../src/main/resources/ui/app/routes/index.js | 2 +- .../src/main/resources/ui/app/routes/job.js | 29 +- .../ui/app/services/dashboard-context.js | 38 ++ .../main/resources/ui/app/services/save-job.js | 42 ++ .../src/main/resources/ui/app/styles/app.less | 72 ++- .../app/templates/components/bundle-config.hbs | 42 +- .../components/bundle-coord-config.hbs | 17 +- .../templates/components/bundle-job-details.hbs | 12 +- .../components/bundle-version-settings.hbs | 45 ++ .../app/templates/components/coord-config.hbs | 359 +++++++-------- .../templates/components/coord-job-details.hbs | 6 +- .../components/coord-version-settings.hbs | 45 ++ .../templates/components/designer-workspace.hbs | 119 ++--- .../app/templates/components/flow-designer.hbs | 154 +++++-- .../app/templates/components/hdfs-browser.hbs | 2 +- .../templates/components/import-from-stream.hbs | 63 +++ .../ui/app/templates/components/job-config.hbs | 10 +- .../ui/app/templates/components/job-details.hbs | 50 ++- .../ui/app/templates/components/job-row.hbs | 14 +- .../app/templates/components/preview-dialog.hbs | 5 +- .../components/search-create-new-bar.hbs | 2 +- .../app/templates/components/search-table.hbs | 3 +- .../templates/components/workflow-actions.hbs | 8 +- .../app/templates/components/workflow-icon.hbs | 24 + .../components/workflow-job-details.hbs | 28 +- .../main/resources/ui/app/templates/design.hbs | 2 +- .../ui/app/templates/design/dashboardtab.hbs | 30 ++ .../ui/app/templates/design/jobtab.hbs | 21 + .../src/main/resources/ui/app/templates/job.hbs | 2 +- .../main/resources/ui/app/utils/common-utils.js | 3 + .../main/resources/ui/app/utils/constants.js | 2 +- .../wfmanager/src/main/resources/ui/bower.json | 3 +- .../src/main/resources/ui/ember-cli-build.js | 7 + .../src/main/resources/ui/package.json | 4 +- .../components/bundle-version-settings-test.js | 40 ++ .../components/coord-version-settings-test.js | 40 ++ .../components/import-from-stream-test.js | 41 ++ .../components/workflow-icon-test.js | 40 ++ .../unit/routes/design/dashboardtab-test.js | 27 ++ .../unit/services/dashboard-context-test.js | 28 ++ .../ui/tests/unit/services/save-job-test.js | 29 ++ 92 files changed, 3538 insertions(+), 635 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/pom.xml ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/pom.xml b/contrib/views/wfmanager/pom.xml index d4aedf3..53d26a2 100644 --- a/contrib/views/wfmanager/pom.xml +++ b/contrib/views/wfmanager/pom.xml @@ -157,7 +157,7 @@ <plugin> <groupId>com.github.eirslett</groupId> <artifactId>frontend-maven-plugin</artifactId> - <version>0.0.16</version> + <version>1.1</version> <configuration> <nodeVersion>v4.5.0</nodeVersion> <npmVersion>2.15.0</npmVersion> @@ -213,12 +213,11 @@ <goal>exec</goal> </goals> <configuration> - <workingDirectory>${basedir}/src/main/resources/ui</workingDirectory> - <executable>node/node</executable> + <workingDirectory>${ui.directory}</workingDirectory> + <executable>${ui.directory}/node_modules/.bin/${ember.executable}</executable> <arguments> - <argument>node_modules/.bin/ember</argument> <argument>build</argument> - + <argument>-prod</argument> </arguments> </configuration> </execution> @@ -246,24 +245,6 @@ <includeScope>runtime</includeScope> </configuration> </execution> - <execution> - <id>copy-artifact</id> - <phase>package</phase> - <goals> - <goal>copy</goal> - </goals> - <configuration> - <artifactItems> - <artifactItem> - <groupId>${project.groupId}</groupId> - <artifactId>${project.artifactId}</artifactId> - <version>${project.version}</version> - <type>${project.packaging}</type> - </artifactItem> - </artifactItems> - <outputDirectory>${views.jars.dir.rel}</outputDirectory> - </configuration> - </execution> </executions> </plugin> </plugins> @@ -303,6 +284,7 @@ </activation> <properties> <node.executable>node.exe</node.executable> + <ember.executable>ember.cmd</ember.executable> <skip.nodegyp.chmod>true</skip.nodegyp.chmod> </properties> </profile> @@ -315,6 +297,7 @@ </activation> <properties> <node.executable>node</node.executable> + <ember.executable>ember</ember.executable> <skip.nodegyp.chmod>false</skip.nodegyp.chmod> </properties> </profile> http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/AmbariIOUtil.java ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/AmbariIOUtil.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/AmbariIOUtil.java new file mode 100644 index 0000000..93447b7 --- /dev/null +++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/AmbariIOUtil.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.oozie.ambari.view; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +import org.apache.ambari.view.URLStreamProvider; +import org.apache.ambari.view.ViewContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AmbariIOUtil { + private final static Logger LOGGER = LoggerFactory + .getLogger(AmbariIOUtil.class); + private ViewContext viewContext; + + public AmbariIOUtil(ViewContext viewContext) { + super(); + this.viewContext = viewContext; + } + + public InputStream readFromUrl(String urlToRead, String method, + String body, Map<String, String> newHeaders) { + URLStreamProvider streamProvider = viewContext.getURLStreamProvider(); + InputStream stream = null; + try { + if (isSecurityEnabled()) { + stream = streamProvider.readAsCurrent(urlToRead, method, body, + newHeaders); + + } else { + stream = streamProvider.readFrom(urlToRead, method, body, + newHeaders); + } + } catch (IOException e) { + LOGGER.error("error talking to oozie", e); + throw new RuntimeException(e); + } + return stream; + } + + private boolean isSecurityEnabled() { + String authType = viewContext.getCluster().getConfigurationValue( + "core-site", "hadoop.security.authentication"); + LOGGER.info("Auth Type=" + authType); + return !"simple".equalsIgnoreCase(authType); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/HDFSFileUtils.java ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/HDFSFileUtils.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/HDFSFileUtils.java index 58c3980..327d8fc 100644 --- a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/HDFSFileUtils.java +++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/HDFSFileUtils.java @@ -17,6 +17,7 @@ */ package org.apache.oozie.ambari.view; +import java.io.FileNotFoundException; import java.io.IOException; import org.apache.ambari.view.ViewContext; @@ -24,6 +25,7 @@ import org.apache.ambari.view.utils.hdfs.HdfsApi; import org.apache.ambari.view.utils.hdfs.HdfsUtil; import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FSDataOutputStream; +import org.apache.hadoop.fs.FileStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,10 +38,10 @@ public class HDFSFileUtils { super(); this.viewContext = viewContext; } + public boolean fileExists(String path) { - boolean fileExists; try { - fileExists = getHdfsgetApi().exists(path); + return getHdfsgetApi().exists(path); } catch (IOException e) { LOGGER.error(e.getMessage(), e); throw new RuntimeException(e); @@ -47,11 +49,9 @@ public class HDFSFileUtils { LOGGER.error(e.getMessage(), e); throw new RuntimeException(e); } - LOGGER.info("FILE exists for [" + path + "] returned [" + fileExists - + "]"); - return fileExists; } - public FSDataInputStream read(String filePath)throws IOException{ + + public FSDataInputStream read(String filePath) throws IOException { FSDataInputStream is; try { is = getHdfsgetApi().open(filePath); @@ -60,19 +60,28 @@ public class HDFSFileUtils { } return is; } - public String createWorkflowFile( String workflowFile,String postBody, - boolean overwrite) throws IOException { + + public String writeToFile(String filePath, String content, boolean overwrite) + throws IOException { FSDataOutputStream fsOut; try { - fsOut = getHdfsgetApi().create(workflowFile, - overwrite); + fsOut = getHdfsgetApi().create(filePath, overwrite); } catch (InterruptedException e) { throw new RuntimeException(e); } - fsOut.write(postBody.getBytes()); + fsOut.write(content.getBytes()); fsOut.close(); - return workflowFile; + return filePath; + } + + public void deleteFile(String filePath) throws IOException { + try { + getHdfsgetApi().delete(filePath, false); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } } + private HdfsApi getHdfsgetApi() { try { return HdfsUtil.connectToHDFSApi(viewContext); @@ -84,4 +93,17 @@ public class HDFSFileUtils { } } + public FileStatus getFileStatus(String filePath) { + try { + return getHdfsgetApi().getFileStatus(filePath); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java index 0533f04..08a166d 100644 --- a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java +++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieProxyImpersonator.java @@ -45,13 +45,13 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.StreamingOutput; import javax.ws.rs.core.UriInfo; -import org.apache.ambari.view.URLStreamProvider; import org.apache.ambari.view.ViewContext; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.exception.ExceptionUtils; -import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.security.AccessControlException; +import org.apache.oozie.ambari.view.workflowmanager.WorkflowManagerService; +import org.apache.oozie.ambari.view.workflowmanager.WorkflowsManagerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -81,9 +81,13 @@ public class OozieProxyImpersonator { private static final String SERVICE_URI_PROP = "oozie.service.uri"; private static final String DEFAULT_SERVICE_URI = "http://sandbox.hortonworks.com:11000/oozie"; - private Utils utils=new Utils(); - private OozieUtils oozieUtils=new OozieUtils(); + private Utils utils = new Utils(); + private AmbariIOUtil ambariIOUtil; + private OozieUtils oozieUtils = new OozieUtils(); private HDFSFileUtils hdfsFileUtils; + private WorkflowFilesService workflowFilesService; + //private WorkflowManagerService workflowManagerService; + private static enum ErrorCodes { OOZIE_SUBMIT_ERROR("error.oozie.submit", "Oozie Submit error"), OOZIE_IO_ERROR( "error.oozie.io", "Oozie I/O error"), FILE_ACCESS_ACL_ERROR( @@ -111,10 +115,14 @@ public class OozieProxyImpersonator { @Inject public OozieProxyImpersonator(ViewContext viewContext) { this.viewContext = viewContext; - hdfsFileUtils=new HDFSFileUtils(viewContext); + hdfsFileUtils = new HDFSFileUtils(viewContext); + workflowFilesService = new WorkflowFilesService(hdfsFileUtils); + ambariIOUtil=new AmbariIOUtil(viewContext); + //workflowManagerService = new WorkflowManagerService(viewContext); LOGGER.info(String.format( "OozieProxyImpersonator initialized for instance: %s", viewContext.getInstanceName())); + } @Path("/fileServices") @@ -122,6 +130,11 @@ public class OozieProxyImpersonator { return new FileServices(viewContext); } + @Path("/wfprojects") + public WorkflowsManagerResource workflowsManagerResource() { + return new WorkflowsManagerResource(viewContext); + } + @GET @Path("/getCurrentUserName") public Response getCurrentUserName() { @@ -171,9 +184,12 @@ public class OozieProxyImpersonator { } postBody = utils.formatXml(postBody); try { - String filePath = hdfsFileUtils.createWorkflowFile(getWorkflowFileName(appPath),postBody, overwrite); + String filePath = workflowFilesService.createWorkflowFile(appPath, + postBody, overwrite); LOGGER.info(String.format( "submit workflow job done. filePath=[%s]", filePath)); + /* workflowManagerService.saveWorkflow(appPath, JobType.WORKFLOW, + "todo description", viewContext.getUsername());*/ return Response.ok().build(); } catch (Exception ex) { LOGGER.error(ex.getMessage(), ex); @@ -181,6 +197,125 @@ public class OozieProxyImpersonator { } } + + @POST + @Path("/publishAsset") + @Consumes({ MediaType.TEXT_PLAIN + "," + MediaType.TEXT_XML }) + public Response publishAsset(String postBody, @Context HttpHeaders headers, + @Context UriInfo ui, @QueryParam("uploadPath") String uploadPath, + @DefaultValue("false") @QueryParam("overwrite") Boolean overwrite) { + LOGGER.info("publish asset called"); + if (StringUtils.isEmpty(uploadPath)) { + throw new RuntimeException("upload path can't be empty."); + } + uploadPath = uploadPath.trim(); + Response dryRunResponse = validateAsset(headers, postBody, ui.getQueryParameters()); + if (dryRunResponse.getStatus() == 200) { + return saveAsset(postBody, uploadPath, overwrite); + } + return dryRunResponse; + } + + private Response validateAsset(HttpHeaders headers, String postBody, MultivaluedMap<String, String> queryParams) { + String workflowXml = oozieUtils.generateWorkflowXml(postBody); + try { + String tempWfPath = "/user/"+viewContext.getUsername()+"/tmpooziewfs/tempwf.xml"; + hdfsFileUtils.writeToFile(tempWfPath, workflowXml, true); + queryParams.put("oozieparam.action",getAsList("dryrun")); + queryParams.put("oozieconfig.rerunOnFailure",getAsList("false")); + queryParams.put("oozieconfig.useSystemLibPath",getAsList("true")); + queryParams.put("resourceManager",getAsList("useDefault")); + String dryRunResp = submitWorkflowJobToOozie(headers,tempWfPath,queryParams,JobType.WORKFLOW); + LOGGER.info(String.format("resp from validating asset=[%s]",dryRunResp)); + if (dryRunResp != null && dryRunResp.trim().startsWith("{")) { + return Response.status(Response.Status.OK).entity(dryRunResp).build(); + } else { + HashMap<String, String> resp = new HashMap<String, String>(); + resp.put("status", ErrorCodes.OOZIE_SUBMIT_ERROR.getErrorCode()); + resp.put("message", dryRunResp); + //resp.put("stackTrace", dryRunResp); + return Response.status(Response.Status.BAD_REQUEST).entity(resp).build(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private List<String> getAsList(String string) { + ArrayList<String> li=new ArrayList<>(1); + li.add(string); + return li; + } + + private Response saveAsset(String postBody, String uploadPath, + Boolean overwrite) { + uploadPath = workflowFilesService.getAssetFileName(uploadPath); + if (!overwrite) { + boolean fileExists = hdfsFileUtils.fileExists(uploadPath); + if (fileExists) { + return getFileExistsResponse(); + } + } + postBody = utils.formatXml(postBody); + try { + String filePath = workflowFilesService.createAssetFile(uploadPath, + postBody, overwrite); + LOGGER.info(String.format( + "publish asset job done. filePath=[%s]", filePath)); + return Response.ok().build(); + } catch (Exception ex) { + LOGGER.error(ex.getMessage(), ex); + return getRespCodeForException(ex); + } + } + + @POST + @Path("/saveWorkflowDraft") + @Consumes({ MediaType.TEXT_PLAIN + "," + MediaType.TEXT_XML }) + public Response saveDraft(String postBody, @Context HttpHeaders headers, + @Context UriInfo ui, @QueryParam("app.path") String appPath, + @DefaultValue("false") @QueryParam("overwrite") Boolean overwrite) + throws IOException { + LOGGER.info("save workflow called"); + if (StringUtils.isEmpty(appPath)) { + throw new RuntimeException("app path can't be empty."); + } + appPath = appPath.trim(); + workflowFilesService.saveDraft(appPath, postBody, overwrite); + /* workflowManagerService.saveWorkflow(appPath, JobType.WORKFLOW, + "todo description", viewContext.getUsername());*/ + return Response.ok().build(); + } + + @GET + @Path("/readWorkflowDraft") + public Response readDraft(@QueryParam("workflowXmlPath") String workflowPath) { + if (StringUtils.isEmpty(workflowPath)) { + throw new RuntimeException("workflowXmlPath can't be empty."); + } + try { + final InputStream is = workflowFilesService.readDraft(workflowPath); + StreamingOutput streamer = new StreamingOutput() { + @Override + public void write(OutputStream os) throws IOException, + WebApplicationException { + IOUtils.copy(is, os); + is.close(); + os.close(); + } + }; + return Response.ok(streamer).status(200).build(); + } catch (IOException e) { + return getRespCodeForException(e); + } + } + + @POST + @Path("/discardWorkflowDraft") + public Response discardDraft(@QueryParam("workflowXmlPath") String workflowPath) throws IOException{ + workflowFilesService.discardDraft(workflowPath); + return Response.ok().build(); + } private Response submitJobInternal(String postBody, HttpHeaders headers, UriInfo ui, String appPath, Boolean overwrite, JobType jobType) { @@ -196,7 +331,8 @@ public class OozieProxyImpersonator { } postBody = utils.formatXml(postBody); try { - String filePath = hdfsFileUtils.createWorkflowFile(getWorkflowFileName(appPath),postBody,overwrite); + String filePath = hdfsFileUtils.writeToFile(appPath, postBody, + overwrite); LOGGER.info(String.format( "submit workflow job done. filePath=[%s]", filePath)); } catch (Exception ex) { @@ -204,6 +340,8 @@ public class OozieProxyImpersonator { return getRespCodeForException(ex); } + /* workflowManagerService.saveWorkflow(appPath, jobType, + "todo description", viewContext.getUsername());*/ String response = submitWorkflowJobToOozie(headers, appPath, ui.getQueryParameters(), jobType); if (response != null && response.trim().startsWith("{")) { @@ -226,21 +364,20 @@ public class OozieProxyImpersonator { ErrorCodes.FILE_ACCESS_ACL_ERROR.getDescription(), ex); return Response.status(Response.Status.BAD_REQUEST) .entity(errorDetails).build(); - }else if (ex instanceof IOException){ + } else if (ex instanceof IOException) { HashMap<String, String> errorDetails = getErrorDetails( ErrorCodes.FILE_ACCESS_UNKNOWN_ERROR.getErrorCode(), ErrorCodes.FILE_ACCESS_UNKNOWN_ERROR.getDescription(), ex); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity(errorDetails).build(); - }else { + } else { HashMap<String, String> errorDetails = getErrorDetails( ErrorCodes.FILE_ACCESS_UNKNOWN_ERROR.getErrorCode(), ErrorCodes.FILE_ACCESS_UNKNOWN_ERROR.getDescription(), ex); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity(errorDetails).build(); } - - + } private Response getFileExistsResponse() { @@ -250,18 +387,14 @@ public class OozieProxyImpersonator { return Response.status(Response.Status.BAD_REQUEST).entity(resp) .build(); } - - private String getWorkflowFileName(String appPath) { - String workflowFile = null; - if (appPath.endsWith(".xml")) { - workflowFile = appPath; - } else { - workflowFile = appPath + (appPath.endsWith("/") ? "" : "/") - + "workflow.xml"; - } - return workflowFile; + + @GET + @Path("/readWorkflowDetail") + public Response isDraftAvailable(@QueryParam("workflowXmlPath") String workflowPath){ + WorkflowFileInfo workflowDetails = workflowFilesService.getWorkflowDetails(workflowPath); + return Response.ok(workflowDetails).build(); } - + @GET @Path("/readWorkflowXml") public Response readWorkflowXxml( @@ -270,7 +403,7 @@ public class OozieProxyImpersonator { throw new RuntimeException("workflowXmlPath can't be empty."); } try { - final FSDataInputStream is = hdfsFileUtils.read(workflowPath); + final InputStream is = workflowFilesService.readWorkflowXml(workflowPath); StreamingOutput streamer = new StreamingOutput() { @Override public void write(OutputStream os) throws IOException, @@ -281,7 +414,7 @@ public class OozieProxyImpersonator { } }; return Response.ok(streamer).status(200).build(); - } catch(IOException e){ + } catch (IOException e) { return getRespCodeForException(e); } } @@ -405,7 +538,7 @@ public class OozieProxyImpersonator { queryParams.put("config.nameNode", nameNodes); } - HashMap<String, String> workflowConigs = getWorkflowConfigs(filePath, + Map<String, String> workflowConigs = getWorkflowConfigs(filePath, queryParams, jobType, nameNode); String configXMl = oozieUtils.generateConfigXml(workflowConigs); LOGGER.info("Config xml==" + configXMl); @@ -415,7 +548,7 @@ public class OozieProxyImpersonator { + "/v2/jobs?" + getJobSumbitOozieParams(queryParams), HttpMethod.POST, configXMl, customHeaders); - LOGGER.info("REsp from oozie status entity==" + LOGGER.info("Resp from oozie status entity==" + serviceResponse.getEntity()); if (serviceResponse.getEntity() instanceof String) { return (String) serviceResponse.getEntity(); @@ -425,7 +558,7 @@ public class OozieProxyImpersonator { } - private HashMap<String, String> getWorkflowConfigs(String filePath, + private Map<String, String> getWorkflowConfigs(String filePath, MultivaluedMap<String, String> queryParams, JobType jobType, String nameNode) { HashMap<String, String> workflowConigs = new HashMap<String, String>(); @@ -466,7 +599,8 @@ public class OozieProxyImpersonator { workflowConigs.put(OOZIE_WF_RERUN_FAILNODES_CONF_KEY, "true"); } workflowConigs.put("user.name", viewContext.getUsername()); - workflowConigs.put(oozieUtils.getJobPathPropertyKey(jobType), nameNode + filePath); + workflowConigs.put(oozieUtils.getJobPathPropertyKey(jobType), nameNode + + filePath); return workflowConigs; } @@ -497,10 +631,13 @@ public class OozieProxyImpersonator { uiURI = uiURI.substring(index); String serviceURI = getServiceUri(); serviceURI += uiURI; - MultivaluedMap<String, String> params = addOrReplaceUserName(ui.getQueryParameters()); - return serviceURI+utils.convertParamsToUrl(params); + MultivaluedMap<String, String> params = addOrReplaceUserName(ui + .getQueryParameters()); + return serviceURI + utils.convertParamsToUrl(params); } - private MultivaluedMap<String, String> addOrReplaceUserName(MultivaluedMap<String, String> parameters){ + + private MultivaluedMap<String, String> addOrReplaceUserName( + MultivaluedMap<String, String> parameters) { for (Map.Entry<String, List<String>> entry : parameters.entrySet()) { if ("user.name".equals(entry.getKey())) { ArrayList<String> vals = new ArrayList<String>(1); @@ -521,7 +658,7 @@ public class OozieProxyImpersonator { String method, String body) throws Exception { return consumeService(headers, urlToRead, method, body, null); } - + private Response consumeService(HttpHeaders headers, String urlToRead, String method, String body, Map<String, String> customHeaders) { Response response = null; @@ -539,8 +676,8 @@ public class OozieProxyImpersonator { .entity(stringResponse).type(MediaType.TEXT_PLAIN).build(); } else { response = Response.status(Response.Status.OK) - .entity(stringResponse).type(utils.deduceType(stringResponse)) - .build(); + .entity(stringResponse) + .type(utils.deduceType(stringResponse)).build(); } return response; } @@ -558,36 +695,7 @@ public class OozieProxyImpersonator { } LOGGER.info(String.format("Proxy request for url: [%s] %s", method, urlToRead)); - - return readFromUrl(urlToRead, method, body, newHeaders); - } - private InputStream readFromUrl(String urlToRead, String method, String body, - Map<String, String> newHeaders) { - URLStreamProvider streamProvider = viewContext.getURLStreamProvider(); - InputStream stream = null; - try { - if (isSecurityEnabled()) { - stream = streamProvider.readAsCurrent(urlToRead, method, body, - newHeaders); - - } else { - stream = streamProvider.readFrom(urlToRead, method, body, - newHeaders); - } - } catch (IOException e) { - LOGGER.error("error talking to oozie", e); - throw new RuntimeException(e); - } - return stream; + return ambariIOUtil.readFromUrl(urlToRead, method, body, newHeaders); } - - - private boolean isSecurityEnabled() { - String authType = viewContext.getCluster().getConfigurationValue( - "core-site", "hadoop.security.authentication"); - LOGGER.info("Auth Type=" + authType); - return !"simple".equalsIgnoreCase(authType); - } - } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java index 170132f..f002102 100644 --- a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java +++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/OozieUtils.java @@ -17,6 +17,8 @@ */ package org.apache.oozie.ambari.view; +import java.io.IOException; +import java.io.StringReader; import java.util.Map; import javax.xml.parsers.DocumentBuilder; @@ -27,6 +29,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; public class OozieUtils { private final static Logger LOGGER = LoggerFactory @@ -68,4 +72,52 @@ public class OozieUtils { } throw new RuntimeException("Unknown Job Type"); } + + public String generateWorkflowXml(String actionNodeXml) { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db; + try { + db = dbf.newDocumentBuilder(); + Document doc = db.newDocument(); + + Element workflowElement = doc.createElement("workflow-app"); + workflowElement.setAttribute("name", "testWorkflow"); + workflowElement.setAttribute("xmlns", "uri:oozie:workflow:0.5"); + doc.appendChild(workflowElement); + + Element startElement = doc.createElement("start"); + startElement.setAttribute("to", "testAction"); + workflowElement.appendChild(startElement); + + Element actionElement = doc.createElement("action"); + actionElement.setAttribute("name", "testAction"); + Element actionSettingsElement = db.parse(new InputSource(new StringReader(actionNodeXml))).getDocumentElement(); + actionElement.appendChild(doc.importNode(actionSettingsElement, true)); + workflowElement.appendChild(actionElement); + + Element actionOkTransitionElement = doc.createElement("ok"); + actionOkTransitionElement.setAttribute("to", "end"); + actionElement.appendChild(actionOkTransitionElement); + + Element actionErrorTransitionElement = doc.createElement("error"); + actionErrorTransitionElement.setAttribute("to", "kill"); + actionElement.appendChild(actionErrorTransitionElement); + + Element killElement = doc.createElement("kill"); + killElement.setAttribute("name", "kill"); + Element killMessageElement = doc.createElement("message"); + killMessageElement.setTextContent("Kill node message"); + killElement.appendChild(killMessageElement); + workflowElement.appendChild(killElement); + + Element endElement = doc.createElement("end"); + endElement.setAttribute("name", "end"); + workflowElement.appendChild(endElement); + + return utils.generateXml(doc); + } catch (ParserConfigurationException | SAXException | IOException e) { + LOGGER.error("error in generating workflow xml", e); + throw new RuntimeException(e); + } + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFileInfo.java ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFileInfo.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFileInfo.java new file mode 100644 index 0000000..6dbf30e --- /dev/null +++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFileInfo.java @@ -0,0 +1,64 @@ +/** + * 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.oozie.ambari.view; + +public class WorkflowFileInfo { + private String workflowPath; + private String draftPath; + private Boolean draftExists; + private Boolean isDraftCurrent=false; + public Boolean getIsDraftCurrent() { + return isDraftCurrent; + } + public void setIsDraftCurrent(Boolean isDraftCurrent) { + this.isDraftCurrent = isDraftCurrent; + } + private Long workflowModificationTime; + private Long draftModificationTime; + public String getWorkflowPath() { + return workflowPath; + } + public void setWorkflowPath(String workflowPath) { + this.workflowPath = workflowPath; + } + public String getDraftPath() { + return draftPath; + } + public void setDraftPath(String draftPath) { + this.draftPath = draftPath; + } + public Boolean getDraftExists() { + return draftExists; + } + public void setDraftExists(Boolean draftExists) { + this.draftExists = draftExists; + } + public void setWorkflowModificationTime(Long modificationTime) { + this.workflowModificationTime=modificationTime; + } + public void setDraftModificationTime(Long modificationTime) { + this.draftModificationTime=modificationTime; + } + public Long getWorkflowModificationTime() { + return workflowModificationTime; + } + public Long getDraftModificationTime() { + return draftModificationTime; + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFilesService.java ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFilesService.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFilesService.java new file mode 100644 index 0000000..01bde47 --- /dev/null +++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/WorkflowFilesService.java @@ -0,0 +1,116 @@ +/** + * 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.oozie.ambari.view; + +import java.io.IOException; +import java.io.InputStream; +import org.apache.hadoop.fs.FileStatus; + +public class WorkflowFilesService { + private HDFSFileUtils hdfsFileUtils; + + public WorkflowFilesService(HDFSFileUtils hdfsFileUtils) { + super(); + this.hdfsFileUtils = hdfsFileUtils; + } + + public String createWorkflowFile(String appPath, String content, + boolean overwrite) throws IOException { + return hdfsFileUtils.writeToFile(getWorkflowFileName(appPath), content, + overwrite); + } + + public String createAssetFile(String appPath, String content, + boolean overwrite) throws IOException { + return hdfsFileUtils.writeToFile(appPath, content, + overwrite); + } + + public String saveDraft(String appPath, String content, boolean overwrite) + throws IOException { + return hdfsFileUtils.writeToFile(getWorkflowDrafFileName(appPath), + content, overwrite); + } + + public InputStream readDraft(String appPath) throws IOException { + return hdfsFileUtils.read(getWorkflowDrafFileName(appPath)); + } + public InputStream readWorkflowXml(String appPath) throws IOException { + return hdfsFileUtils.read(getWorkflowFileName(appPath)); + } + + private String getWorkflowDrafFileName(String appPath) { + return getWorkflowFileName(appPath).concat(".draft.json"); + } + + private String getWorkflowFileName(String appPath) { + String workflowFile = null; + if (appPath.endsWith(".xml")) { + workflowFile = appPath; + } else { + workflowFile = appPath + (appPath.endsWith("/") ? "" : "/") + + "workflow.xml"; + } + return workflowFile; + } + + public String getAssetFileName(String appPath) { + String assetFile = null; + if (appPath.endsWith(".xml")) { + assetFile = appPath; + } else { + assetFile = appPath + (appPath.endsWith("/") ? "" : "/") + + "asset.xml"; + } + return assetFile; + } + + public void discardDraft(String workflowPath) throws IOException { + hdfsFileUtils.deleteFile(getWorkflowDrafFileName(workflowPath)); + + } + + public WorkflowFileInfo getWorkflowDetails(String appPath) { + WorkflowFileInfo workflowInfo = new WorkflowFileInfo(); + workflowInfo.setWorkflowPath(getWorkflowFileName(appPath)); + boolean draftExists = hdfsFileUtils + .fileExists(getWorkflowDrafFileName(appPath)); + workflowInfo.setDraftExists(draftExists); + boolean workflowExists = hdfsFileUtils.fileExists(getWorkflowFileName(appPath)); + FileStatus workflowFileStatus = null; + if (workflowExists){ + workflowFileStatus = hdfsFileUtils + .getFileStatus(getWorkflowFileName(appPath)); + workflowInfo.setWorkflowModificationTime(workflowFileStatus + .getModificationTime()); + } + if (draftExists) { + FileStatus draftFileStatus = hdfsFileUtils + .getFileStatus(getWorkflowDrafFileName(appPath)); + workflowInfo.setDraftModificationTime(draftFileStatus + .getModificationTime()); + if (!workflowExists){ + workflowInfo.setIsDraftCurrent(true); + }else{ + workflowInfo.setIsDraftCurrent(draftFileStatus.getModificationTime() + - workflowFileStatus.getModificationTime() > 0); + } + } + return workflowInfo; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/AssetRepo.java ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/AssetRepo.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/AssetRepo.java new file mode 100644 index 0000000..1390ec0 --- /dev/null +++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/AssetRepo.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 + * + * 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.oozie.ambari.view.assets; + +import java.util.Collection; + +import org.apache.ambari.view.DataStore; +import org.apache.oozie.ambari.view.assets.model.ActionAsset; + +public class AssetRepo { + private final DataStore dataStore; + + public AssetRepo(DataStore dataStore) { + super(); + this.dataStore = dataStore; + } + public void saveAsset(ActionAsset asset){ + + } + public void deleteAsset(ActionAsset asset){ + + } + public Collection<ActionAsset>listAllAssets(){ + return null; + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/AssetService.java ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/AssetService.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/AssetService.java new file mode 100644 index 0000000..648a89f --- /dev/null +++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/AssetService.java @@ -0,0 +1,51 @@ +/** + * 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.oozie.ambari.view.assets; + +import java.util.Collection; + +import org.apache.ambari.view.ViewContext; +import org.apache.oozie.ambari.view.assets.model.ActionAsset; + +public class AssetService { + private AssetRepo assetRepo; + + public AssetService(ViewContext viewContext) { + super(); + assetRepo = new AssetRepo(viewContext.getDataStore()); + } + + public Collection<ActionAsset> getAssets() { + + return null; + } + + public Collection<ActionAsset> getPrioritizedAssets() { + Collection<ActionAsset> assets = getAssets(); + // reorder + return assets; + } + + public void addAsset() { + + } + + public void deleteAsset() { + + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/model/ActionAsset.java ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/model/ActionAsset.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/model/ActionAsset.java new file mode 100644 index 0000000..8eb6081 --- /dev/null +++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/assets/model/ActionAsset.java @@ -0,0 +1,60 @@ +/** + * 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.oozie.ambari.view.assets.model; + +import org.apache.oozie.ambari.view.model.BaseModel; + +public class ActionAsset extends BaseModel { + private String id; + private String name; + private String description; + private String assetLocation; + private String type; + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + public String getAssetLocation() { + return assetLocation; + } + public void setAssetLocation(String assetLocation) { + this.assetLocation = assetLocation; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/model/BaseModel.java ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/model/BaseModel.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/model/BaseModel.java new file mode 100644 index 0000000..553ce24 --- /dev/null +++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/model/BaseModel.java @@ -0,0 +1,48 @@ +/** + * 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.oozie.ambari.view.model; + +import java.io.Serializable; + + +public class BaseModel implements Serializable{ + private static final long serialVersionUID = 1L; + private String createdAt; + private String updatedAt; + private String owner; + + public String getCreatedAt() { + return createdAt; + } + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + public String getUpdatedAt() { + return updatedAt; + } + public void setUpdatedAt(String updatedAt) { + this.updatedAt = updatedAt; + } + public String getOwner() { + return owner; + } + public void setOwner(String owner) { + this.owner = owner; + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowManagerService.java ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowManagerService.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowManagerService.java new file mode 100644 index 0000000..4c88454 --- /dev/null +++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowManagerService.java @@ -0,0 +1,76 @@ +/** + * 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.oozie.ambari.view.workflowmanager; + +import java.io.IOException; +import java.util.Collection; +import java.util.Date; + +import org.apache.ambari.view.ViewContext; +import org.apache.oozie.ambari.view.HDFSFileUtils; +import org.apache.oozie.ambari.view.JobType; +import org.apache.oozie.ambari.view.workflowmanager.model.Workflow; + +public class WorkflowManagerService { + + private WorkflowsRepo workflowsRepository; + private HDFSFileUtils hdfsFileUtils; + + public WorkflowManagerService(ViewContext viewContext) { + workflowsRepository = new WorkflowsRepo(viewContext.getDataStore()); + hdfsFileUtils = new HDFSFileUtils(viewContext); + } + + public void saveWorkflow(String path, JobType jobType, String descripton, + String userName) { + // workflowsRepository.getWorkflow(path); + Workflow workflowByPath = getWorkflowByPath(path); + if (workflowByPath == null) { + Workflow wf = new Workflow(); + wf.setOwner(userName); + wf.setType(jobType.name()); + wf.setWorkflowDefinitionPath(path); + Date now = new Date(); + wf.setUpdatedAt(String.valueOf(now.getTime())); + workflowsRepository.updateWorkflow(wf); + } else { + Date now = new Date(); + workflowByPath.setUpdatedAt(String.valueOf(now.getTime())); + workflowsRepository.updateWorkflow(workflowByPath); + } + } + + public Collection<Workflow> getAllWorkflows() { + return workflowsRepository.getAllWorkflows(); + } + + public Workflow getWorkflowByPath(String path) { + return workflowsRepository.getWorkflow(path); + } + + public void deleteWorkflow(String path, Boolean deleteDefinition) { + if (deleteDefinition) { + try { + hdfsFileUtils.deleteFile(path); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + workflowsRepository.deleteWorkflow(path); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsManagerResource.java ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsManagerResource.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsManagerResource.java new file mode 100644 index 0000000..17a3296 --- /dev/null +++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsManagerResource.java @@ -0,0 +1,51 @@ +/** + * 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.oozie.ambari.view.workflowmanager; + +import java.util.HashMap; +import java.util.Map; + +import javax.ws.rs.DELETE; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.QueryParam; + +import org.apache.ambari.view.ViewContext; + +public class WorkflowsManagerResource { + private WorkflowManagerService workflowManagerService; + + public WorkflowsManagerResource(ViewContext viewContext) { + super(); + this.workflowManagerService=new WorkflowManagerService(viewContext); + } + + @GET + public Map<String,Object> getWorkflows(){ + HashMap<String,Object> result=new HashMap<>(); + result.put("wfprojects", workflowManagerService.getAllWorkflows()); + return result; + } + + + @DELETE + public void deleteWorkflow( @QueryParam("worfkflowPath") String path, + @DefaultValue("false") @QueryParam("deleteDefinition") Boolean deleteDefinition){ + workflowManagerService.deleteWorkflow(path,deleteDefinition); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsRepo.java ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsRepo.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsRepo.java new file mode 100644 index 0000000..978c059 --- /dev/null +++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/WorkflowsRepo.java @@ -0,0 +1,69 @@ +/** + * 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.oozie.ambari.view.workflowmanager; + +import java.util.Collection; + +import org.apache.ambari.view.DataStore; +import org.apache.ambari.view.PersistenceException; +import org.apache.oozie.ambari.view.workflowmanager.model.Workflow; + +public class WorkflowsRepo { + private final DataStore dataStore; + + public WorkflowsRepo(DataStore dataStore) { + super(); + this.dataStore=dataStore; + } + public Collection<Workflow> getAllWorkflows(){ + try { + return dataStore.findAll(Workflow.class,null); + } catch (PersistenceException e) { + throw new RuntimeException(e); + } + } + public void deleteWorkflow(String workflowPath){ + try { + Workflow workflow = this.getWorkflow(workflowPath); + this.dataStore.remove(workflow); + } catch (PersistenceException e) { + throw new RuntimeException(e); + } + } + public void createWorkflow(Workflow wf){ + try { + this.dataStore.store(wf); + } catch (PersistenceException e) { + throw new RuntimeException(e); + } + } + public void updateWorkflow(Workflow wf){ + try { + this.dataStore.store(wf); + } catch (PersistenceException e) { + throw new RuntimeException(e); + } + } + public Workflow getWorkflow(String path) { + try { + return this.dataStore.find(Workflow.class, "workflowDefinitionPath='"+path+"'"); + } catch (PersistenceException e) { + throw new RuntimeException(e); + } + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/model/Workflow.java ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/model/Workflow.java b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/model/Workflow.java new file mode 100644 index 0000000..ad5f48b --- /dev/null +++ b/contrib/views/wfmanager/src/main/java/org/apache/oozie/ambari/view/workflowmanager/model/Workflow.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 + * <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.oozie.ambari.view.workflowmanager.model; + +import org.apache.oozie.ambari.view.model.BaseModel; + +public class Workflow extends BaseModel{ + private static final long serialVersionUID = 1L; + private String id = null; + private String name; + private String desciption; + private String workflowDefinitionPath; + private String type; + private String isDraft; + private String definitionMissing;//true or not if path is fine. + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getWorkflowDefinitionPath() { + return workflowDefinitionPath; + } + + public void setWorkflowDefinitionPath(String workflowDefinitionPath) { + this.workflowDefinitionPath = workflowDefinitionPath; + } + + public String getIsDraft() { + return isDraft; + } + + public void setIsDraft(String isDraft) { + this.isDraft = isDraft; + } + + public String getDesciption() { + return desciption; + } + + public void setDesciption(String desciption) { + this.desciption = desciption; + } + + public String getDefinitionMissing() { + return definitionMissing; + } + + public void setDefinitionMissing(String definitionMissing) { + this.definitionMissing = definitionMissing; + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js index 2799db5..4f409a1 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-config.js @@ -20,6 +20,7 @@ import {BundleGenerator} from '../domain/bundle/bundle-xml-generator'; import {BundleXmlImporter} from '../domain/bundle/bundle-xml-importer'; import { validator, buildValidations } from 'ember-cp-validations'; import Constants from '../utils/constants'; +import SchemaVersions from '../domain/schema-versions'; const Validations = buildValidations({ 'bundle.name': validator('presence', { @@ -41,6 +42,8 @@ const Validations = buildValidations({ export default Ember.Component.extend(Ember.Evented, Validations, { bundle : null, + errors: Ember.A([]), + schemaVersions : SchemaVersions.create({}), propertyExtractor : Ember.inject.service('property-extractor'), fileBrowser : Ember.inject.service('file-browser'), workspaceManager : Ember.inject.service('workspace-manager'), @@ -107,7 +110,8 @@ export default Ember.Component.extend(Ember.Evented, Validations, { displayValue : '', type : 'date' }, - coordinators : null + coordinators : null, + schemaVersions : this.get("schemaVersions") }); }, importSampleBundle (){ @@ -156,9 +160,11 @@ export default Ember.Component.extend(Ember.Evented, Validations, { return deferred; }, getBundleFromXml(bundleXml){ - var bundleXmlImporter = BundleXmlImporter.create({}); - var bundle = bundleXmlImporter.importBundle(bundleXml); - this.set("bundle", bundle); + var bundleXmlImporter = BundleXmlImporter.create({schemaVersions: this.get("schemaVersions")}); + var bundleObj = bundleXmlImporter.importBundle(bundleXml, this.get("errors")); + this.set("bundle", bundleObj.bundle); + this.get("errors").clear(); + this.get("errors").pushObjects(bundleObj.errors); }, actions : { closeFileBrowser(){ @@ -220,6 +226,7 @@ export default Ember.Component.extend(Ember.Evented, Validations, { }, resetBundle(){ this.set('bundle', this.createBundle()); + this.set('errors').clear(); }, closeBundleSubmitConfig(){ this.set("showingJobConfig", false); @@ -257,6 +264,9 @@ export default Ember.Component.extend(Ember.Evented, Validations, { }, openTab(type, path){ this.sendAction('openTab', type, path); + }, + showVersionSettings(value){ + this.set('showVersionSettings', value); } } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-coord-config.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-coord-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-coord-config.js index 229b2cc..2280f82 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-coord-config.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-coord-config.js @@ -99,7 +99,7 @@ export default Ember.Component.extend(Validations, { deferred.promise.then(function(data){ var x2js = new X2JS(); var coordJson = x2js.xml_str2json(data); - this.set('coordinatorName', coordJson["coordinator-app"]._name); + this.set('coordinator.name', coordJson["coordinator-app"]._name); }.bind(this)).catch(function(){ this.set('coordinatorName', null); }.bind(this)); http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-version-settings.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-version-settings.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-version-settings.js new file mode 100644 index 0000000..3bd6653 --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/bundle-version-settings.js @@ -0,0 +1,49 @@ +/* +* 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. +*/ + +import Ember from 'ember'; +import Constants from '../utils/constants'; + +export default Ember.Component.extend({ + initialize : function(){ + this.set('currentBundleVersion', this.get('schemaVersions').getCurrentBundleVersion()); + this.set('bundleSchemaVersions', this.get('schemaVersions').getBundleVersions()); + this.get('schemaVersions').createCopy(); + }.on('init'), + BundleVersionObserver : Ember.observer('currentBundleVersion',function(){ + this.get('schemaVersions').setCurrentBundleVersion(this.get('currentBundleVersion')); + }), + rendered : function(){ + this.$('#version-settings-dialog').modal({ + backdrop: 'static', + keyboard: false + }); + this.$('#version-settings-dialog').modal('show'); + this.$('#version-settings-dialog').modal().on('hidden.bs.modal', function() { + this.sendAction('showVersionSettings', false); + }.bind(this)); + }.on('didInsertElement'), + actions : { + save (){ + this.$('#version-settings-dialog').modal('hide'); + }, + cancel (){ + this.get('schemaVersions').rollBack(); + this.$('#version-settings-dialog').modal('hide'); + } + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js index 57fcdf8..23d1955 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-config.js @@ -19,6 +19,7 @@ import {Coordinator} from '../domain/coordinator/coordinator'; import {CoordinatorGenerator} from '../domain/coordinator/coordinator-xml-generator'; import {CoordinatorXmlImporter} from '../domain/coordinator/coordinator-xml-importer'; import {SlaInfo} from '../domain/sla-info'; +import SchemaVersions from '../domain/schema-versions'; import Constants from '../utils/constants'; import { validator, buildValidations } from 'ember-cp-validations'; @@ -42,6 +43,8 @@ const Validations = buildValidations({ export default Ember.Component.extend(Validations, Ember.Evented, { coordinator : null, + errors: Ember.A([]), + schemaVersions : SchemaVersions.create({}), childComponents : new Map(), fileBrowser : Ember.inject.service('file-browser'), propertyExtractor : Ember.inject.service('property-extractor'), @@ -204,18 +207,20 @@ export default Ember.Component.extend(Validations, Ember.Evented, { } }, controls : Ember.A([]), - slainfo : SlaInfo.create({}) + slainfo : SlaInfo.create({}), + schemaVersions : this.get("schemaVersions") }); }, importSampleCoordinator (){ + var self = this; var deferred = Ember.RSVP.defer(); Ember.$.ajax({ url: "/sampledata/coordinator.xml", dataType: "text", cache:false, success: function(data) { - var coordinatorXmlImporter = CoordinatorXmlImporter.create({}); - var coordinator = coordinatorXmlImporter.importCoordinator(data); + var coordinatorXmlImporter = CoordinatorXmlImporter.create({schemaVersions: self.schemaVersions}); + var coordinator = coordinatorXmlImporter.importCoordinator(data, self.errors); deferred.resolve(coordinator); }.bind(this), failure : function(data){ @@ -270,9 +275,12 @@ export default Ember.Component.extend(Validations, Ember.Evented, { return deferred; }, getCoordinatorFromXml(coordinatorXml){ - var coordinatorXmlImporter = CoordinatorXmlImporter.create({}); - var coordinator = coordinatorXmlImporter.importCoordinator(coordinatorXml); + var coordinatorXmlImporter = CoordinatorXmlImporter.create({schemaVersions: this.get("schemaVersions")}); + var coordinatorObj = coordinatorXmlImporter.importCoordinator(coordinatorXml, this.errors); + var coordinator = coordinatorObj.coordinator; this.set("coordinator", coordinator); + this.get("errors").clear(); + this.get("errors").pushObjects(coordinatorObj.errors); this.$('input[name="dataInputType"][value="'+ coordinator.get('dataInputType')+'"]').prop('checked', true); if(coordinator.get('dataInputType') === 'logical'){ this.set('conditionalDataInExists', true); @@ -450,13 +458,16 @@ export default Ember.Component.extend(Validations, Ember.Evented, { }, resetCoordinator(){ this.set('coordinator', this.createNewCoordinator()); + this.get("errors").clear(); }, importCoordinatorTest(){ var deferred = this.importSampleCoordinator(); deferred.promise.then(function(data){ - this.set("coordinator", data); - this.$('input[name="dataInputType"][value="'+ data.get('dataInputType')+'"]').prop('checked', true); - if(data.get('dataInputType') === 'logical'){ + this.set("coordinator", data.coordinator); + this.get("errors").clear(); + this.get("errors").pushObjects(data.errors); + this.$('input[name="dataInputType"][value="'+ data.coordinator.get('dataInputType')+'"]').prop('checked', true); + if(data.coordinator.get('dataInputType') === 'logical'){ this.set('conditionalDataInExists', true); } console.error(this.get('coordinator')); @@ -516,6 +527,9 @@ export default Ember.Component.extend(Validations, Ember.Evented, { }.bind(this)).catch(function(){ this.set('workflowName', null); }.bind(this)); + }, + showVersionSettings(value){ + this.set('showVersionSettings', value); } } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-version-settings.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-version-settings.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-version-settings.js new file mode 100644 index 0000000..6385a44 --- /dev/null +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/coord-version-settings.js @@ -0,0 +1,49 @@ +/* +* 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. +*/ + +import Ember from 'ember'; +import Constants from '../utils/constants'; + +export default Ember.Component.extend({ + initialize : function(){ + this.set('currentCoordinatorVersion', this.get('schemaVersions').getCurrentCoordinatorVersion()); + this.set('coordinatorSchemaVersions', this.get('schemaVersions').getCoordinatorVersions()); + this.get('schemaVersions').createCopy(); + }.on('init'), + CoordinatorVersionObserver : Ember.observer('currentCoordinatorVersion',function(){ + this.get('schemaVersions').setCurrentCoordinatorVersion(this.get('currentCoordinatorVersion')); + }), + rendered : function(){ + this.$('#version-settings-dialog').modal({ + backdrop: 'static', + keyboard: false + }); + this.$('#version-settings-dialog').modal('show'); + this.$('#version-settings-dialog').modal().on('hidden.bs.modal', function() { + this.sendAction('showVersionSettings', false); + }.bind(this)); + }.on('didInsertElement'), + actions : { + save (){ + this.$('#version-settings-dialog').modal('hide'); + }, + cancel (){ + this.get('schemaVersions').rollBack(); + this.$('#version-settings-dialog').modal('hide'); + } + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/resources/ui/app/components/date-with-expr.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/date-with-expr.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/date-with-expr.js index dd9a9ae..541104d 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/components/date-with-expr.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/date-with-expr.js @@ -55,7 +55,6 @@ export default Ember.Component.extend(Validations, { useCurrent: false, showClose : true }); - this.set('dateField.displayValue', undefined); }else{ var dateTimePicker = this.$('input[name="'+this.get('inputName')+'"]').data("DateTimePicker"); if(dateTimePicker){ http://git-wip-us.apache.org/repos/asf/ambari/blob/fb567758/contrib/views/wfmanager/src/main/resources/ui/app/components/designer-workspace.js ---------------------------------------------------------------------- diff --git a/contrib/views/wfmanager/src/main/resources/ui/app/components/designer-workspace.js b/contrib/views/wfmanager/src/main/resources/ui/app/components/designer-workspace.js index a3d64b0..6cbc3dd 100644 --- a/contrib/views/wfmanager/src/main/resources/ui/app/components/designer-workspace.js +++ b/contrib/views/wfmanager/src/main/resources/ui/app/components/designer-workspace.js @@ -15,7 +15,7 @@ * limitations under the License. */ import Ember from 'ember'; - +import CommonUtils from "../utils/common-utils"; export default Ember.Component.extend({ workspaceManager : Ember.inject.service('workspace-manager'), xmlAppPath : null, @@ -42,10 +42,22 @@ export default Ember.Component.extend({ this.get('tabs').forEach((tab)=>{ this.get('tabCounter').set(tab.type, (this.get('tabCounter').get(tab.type)) + 1); }, this); + + Ember.getOwner(this).lookup('route:design').on('openNewTab', function(path){ + this.createNewTab('wf', path); + }.bind(this)); + }.on('init'), elementsInserted : function(){ this.$('.nav-tabs a[data-toggle="tab"]').on('shown.bs.tab', function (e) { - this.get('workspaceManager').setLastActiveTab((this.$(e.target).attr('href').slice(1))); + var id = this.$(e.target).attr('href').slice(1); + this.get('workspaceManager').setLastActiveTab(id); + var tab = this.get('tabs').findBy('id', id); + if(tab.type === 'dashboard'){ + this.sendAction('showDashboard'); + }else{ + this.sendAction('hideDashboard'); + } }.bind(this)); if(this.get('tabs') && this.get('tabs').length > 0){ @@ -54,19 +66,13 @@ export default Ember.Component.extend({ if(!activeTab){ activeTab = this.get('tabs').objectAt(this.get('tabs').length - 1); } - this.$('.nav-tabs a[href="#' + activeTab.id + '"]').tab('show'); - }else{ - if(this.get('hasMultitabSupport')){ - this.createNewTab(this.get('type'), this.get('xmlAppPath')); + if(activeTab.type === 'dashboard'){ + this.createOrshowDashboard(); }else{ - var tab = this.get('tabs').findBy('type', this.get('type')); - if(!tab){ - this.createNewTab(this.get('type'), this.get('xmlAppPath')); - }else{ - Ember.set(tab,'path', this.get('xmlAppPath')); - this.$('.nav-tabs a[href="#' + tab.id + '"]').tab('show'); - } + this.$('.nav-tabs a[href="#' + activeTab.id + '"]').tab('show'); } + }else{ + this.createOrshowDashboard(); } }.on('didInsertElement'), onDestroy : function(){ @@ -100,6 +106,23 @@ export default Ember.Component.extend({ this.get('tabCounter').set(type, ++count); return count; }, + createOrshowDashboard(){ + var dashboardTab = this.get('tabs').findBy('type', 'dashboard'); + if(dashboardTab && dashboardTab.type === 'dashboard'){ + this.$('.nav-tabs a[href="#' + dashboardTab.id + '"]').tab('show'); + }else{ + var tab = { + type : 'dashboard', + id : this.generateTabId(), + name : 'Dashboard' + }; + this.$('.nav-tabs li').removeClass('active'); + this.$('.tab-content .tab-pane').removeClass('active'); + this.get('tabs').pushObject(tab); + this.$('.nav-tabs a[href="#' + tab.id + '"]').tab('show'); + } + this.sendAction('showDashboard'); + }, generateTabId(){ return 'tab-'+ Math.ceil(Math.random() * 100000); }, @@ -109,6 +132,7 @@ export default Ember.Component.extend({ Ember.set(tab, 'context', context); }, show(type){ + this.sendAction('hideDashboard'); if(this.get('hasMultitabSupport')){ this.createNewTab(type); }else{ @@ -120,6 +144,9 @@ export default Ember.Component.extend({ } } }, + showDashboard(){ + this.createOrshowDashboard(); + }, closeTab(index){ if(index < this.get('tabs').length - 1){ var previousTab = this.get('tabs').objectAt(index + 1); @@ -127,6 +154,13 @@ export default Ember.Component.extend({ } this.get('workspaceManager').deleteWorkInProgress(this.get('tabs').objectAt(index).id); this.get('tabs').removeAt(index); + Ember.run.later(()=>{ + var type = this.$('.nav-tabs').find('.active').attr('data-type'); + console.error(type); + if(type === 'dashboard'){ + this.createOrshowDashboard(); + } + }.bind(this)); }, openTab(type, path){ if(this.get('hasMultitabSupport')){ @@ -151,7 +185,10 @@ export default Ember.Component.extend({ }, interceptShow(tab){ if(tab.type === 'wf' && tab.context){ + CommonUtils.setTestContext(tab.context); tab.context.resize(); + }else if(tab.type === 'dashboard'){ + this.sendAction('showDashboard'); } } }
