You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jo...@apache.org on 2014/08/13 22:01:11 UTC
[1/6] git commit: AMBARI-6847. After second canceling of background
operation was opened error (Max Shepel via alexantonenko)
Repository: ambari
Updated Branches:
refs/heads/branch-alerts-dev 56ff1abdb -> 84b988bcb
AMBARI-6847. After second canceling of background operation was opened error (Max Shepel via alexantonenko)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/1eaf6a9e
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/1eaf6a9e
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/1eaf6a9e
Branch: refs/heads/branch-alerts-dev
Commit: 1eaf6a9e92d5620cf7c7952a100e9dc243b6b576
Parents: 56ff1ab
Author: Alex Antonenko <hi...@gmail.com>
Authored: Wed Aug 13 18:26:29 2014 +0300
Committer: Alex Antonenko <hi...@gmail.com>
Committed: Wed Aug 13 18:27:00 2014 +0300
----------------------------------------------------------------------
.../templates/common/host_progress_popup.hbs | 2 +-
ambari-web/app/utils/host_progress_popup.js | 42 ++++++++++++++++----
.../test/utils/host_progress_popup_test.js | 26 ++++++++----
3 files changed, 55 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/1eaf6a9e/ambari-web/app/templates/common/host_progress_popup.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/host_progress_popup.hbs b/ambari-web/app/templates/common/host_progress_popup.hbs
index 939177a..b5df61d 100644
--- a/ambari-web/app/templates/common/host_progress_popup.hbs
+++ b/ambari-web/app/templates/common/host_progress_popup.hbs
@@ -46,7 +46,7 @@
<div class="operation-name-icon-wrap">
<i {{bindAttr class=":service-status servicesInfo.status servicesInfo.icon"}}></i>
{{#if App.supports.abortRequests}}
- <i {{action abortRequest servicesInfo}} {{translateAttr title="hostPopup.bgop.abortRequest.title"}} class="abort-icon icon-remove-circle hidden"></i>
+ <i {{action abortRequest servicesInfo}} {{translateAttr title="hostPopup.bgop.abortRequest.title"}} {{bindAttr class="servicesInfo.abortClassName servicesInfo.abortable:abortable :abort-icon :icon-remove-circle :hidden"}}></i>
{{/if}}
<a href="#">
{{servicesInfo.name}}
http://git-wip-us.apache.org/repos/asf/ambari/blob/1eaf6a9e/ambari-web/app/utils/host_progress_popup.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/host_progress_popup.js b/ambari-web/app/utils/host_progress_popup.js
index 0da534d..25b0899 100644
--- a/ambari-web/app/utils/host_progress_popup.js
+++ b/ambari-web/app/utils/host_progress_popup.js
@@ -68,6 +68,12 @@ App.HostPopup = Em.Object.create({
isPopup: null,
/**
+ * List of aborted requests
+ * @type {Array}
+ */
+ abortedRequests: [],
+
+ /**
* Entering point of this component
* @param {String} serviceName
* @param {Object} controller
@@ -264,8 +270,9 @@ App.HostPopup = Em.Object.create({
this.set("servicesInfo", null);
this.get("inputData").forEach(function (service) {
var status = statuses[service.status] || pendingStatus;
+ var id = service.id;
var newService = Ember.Object.create({
- id: service.id,
+ id: id,
displayName: service.displayName,
progress: service.progress,
status: App.format.taskStatus(status[0]),
@@ -281,8 +288,19 @@ App.HostPopup = Em.Object.create({
sourceRequestScheduleId: service.get('sourceRequestScheduleId'),
contextCommand: service.get('contextCommand')
});
+ if (App.get('supports.abortRequests')) {
+ var abortable = !Em.keys(statuses).contains(service.status) || service.status == 'IN_PROGRESS';
+ if (!abortable) {
+ var abortedRequests = this.get('abortedRequests');
+ this.set('abortedRequests', abortedRequests.without(id));
+ }
+ newService.setProperties({
+ abortable: abortable,
+ abortClassName: 'abort' + id
+ });
+ }
allNewServices.push(newService);
- });
+ }, this);
self.set('servicesInfo', allNewServices);
this.setBackgroundOperationHeader(isServiceListHidden);
}
@@ -482,10 +500,16 @@ App.HostPopup = Em.Object.create({
if (App.get('supports.abortRequests')) {
$(document).on({
mouseenter: function () {
- if ($(this).find('.service-status').hasClass(App.format.taskStatus('IN_PROGRESS')) || $(this).find('.service-status').hasClass(App.format.taskStatus('PENDING'))) {
- App.tooltip($('.abort-icon'));
- $(this).find('.service-status').addClass('hidden');
- $(this).find('.abort-icon').removeClass('hidden');
+ var statusIcon = $(this).find('.service-status');
+ var abortIcon = $(this).find('.abort-icon.abortable');
+ if (abortIcon.length > 0) {
+ var id = parseInt(abortIcon.attr('class').split(' ')[0].match(/\d+/)[0]);
+ var abortedRequests = self.get('abortedRequests');
+ if (!(abortedRequests && abortedRequests.contains(id))) {
+ App.tooltip($('.abort-icon'));
+ statusIcon.addClass('hidden');
+ abortIcon.removeClass('hidden');
+ }
}
},
mouseleave: function () {
@@ -1014,6 +1038,8 @@ App.HostPopup = Em.Object.create({
var requestName = event.context.get('name');
var self = this;
App.showConfirmationPopup(function () {
+ var requestId = event.context.get('id');
+ self.get('controller.abortedRequests').push(requestId);
App.ajax.send({
name: 'background_operations.abort_request',
sender: self,
@@ -1038,7 +1064,9 @@ App.HostPopup = Em.Object.create({
/**
* Method called on unsuccessful sending request to abort operation
*/
- abortRequestErrorCallback: function (xhr, textStatus, error, opt) {
+ abortRequestErrorCallback: function (xhr, textStatus, error, opt, data) {
+ var abortedRequests = this.get('controller.abortedRequests');
+ this.set('controller.abortedRequests', abortedRequests.without(data.requestId));
App.ajax.defaultErrorHandler(xhr, opt.url, 'PUT', xhr.status);
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/1eaf6a9e/ambari-web/test/utils/host_progress_popup_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/host_progress_popup_test.js b/ambari-web/test/utils/host_progress_popup_test.js
index 3a9caa2..b8bc177 100644
--- a/ambari-web/test/utils/host_progress_popup_test.js
+++ b/ambari-web/test/utils/host_progress_popup_test.js
@@ -373,28 +373,40 @@ describe('App.HostPopup', function () {
});
describe('#abortRequestErrorCallback', function () {
+ var popup = App.HostPopup.createPopup();
beforeEach(function () {
sinon.stub(App.ajax, 'get', function(k) {
if (k === 'modalPopup') return null;
return Em.get(App, k);
});
- App.HostPopup.createPopup();
sinon.spy(App.ModalPopup, 'show');
+ sinon.stub(popup, 'get', function(k) {
+ if (k === 'abortedRequests') return [0];
+ return Em.get(popup, k);
+ });
+ popup.get('bodyClass').create().abortRequestErrorCallback({
+ responseText: {
+ message: 'message'
+ },
+ status: 404
+ }, 'status', 'error', {
+ url: 'url'
+ }, {
+ requestId: 0
+ });
});
afterEach(function () {
App.HostPopup.get('isPopup').hide();
App.ModalPopup.show.restore();
+ popup.get.restore();
App.ajax.get.restore();
});
it('should open popup', function () {
- App.HostPopup.get('isPopup.bodyClass').create().abortRequestErrorCallback({
- responseText: {
- message: 'message'
- },
- status: 404
- }, 'url', 'PUT', 404);
expect(App.ModalPopup.show.calledOnce).to.be.true;
});
+ it('should remove current request id from abortedRequests', function () {
+ expect(App.HostPopup.get('abortedRequests')).to.be.empty;
+ });
});
});
[5/6] git commit: AMBARI-6777. Views: view.xml instance changes are
not picked up on redeploy.
Posted by jo...@apache.org.
AMBARI-6777. Views: view.xml instance changes are not picked up on redeploy.
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/1b72f6df
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/1b72f6df
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/1b72f6df
Branch: refs/heads/branch-alerts-dev
Commit: 1b72f6df78a8e683256ed0654146deb59e341490
Parents: f3bd5cc
Author: Siddharth Wagle <sw...@hortonworks.com>
Authored: Wed Aug 13 12:45:35 2014 -0700
Committer: Siddharth Wagle <sw...@hortonworks.com>
Committed: Wed Aug 13 12:45:35 2014 -0700
----------------------------------------------------------------------
.../ambari/server/controller/AmbariServer.java | 4 +-
.../internal/PrivilegeResourceProvider.java | 14 +-
.../internal/ViewPrivilegeResourceProvider.java | 5 +-
.../server/orm/entities/ViewInstanceEntity.java | 25 +++
.../server/upgrade/UpgradeCatalog170.java | 2 +
.../apache/ambari/server/view/ViewRegistry.java | 224 ++++++++++++++-----
.../main/resources/Ambari-DDL-MySQL-CREATE.sql | 2 +-
.../main/resources/Ambari-DDL-Oracle-CREATE.sql | 2 +-
.../resources/Ambari-DDL-Postgres-CREATE.sql | 2 +-
.../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql | 2 +-
.../ambari/server/view/ViewRegistryTest.java | 69 ++++--
11 files changed, 265 insertions(+), 86 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/1b72f6df/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index e6eab3f..98556f9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -68,6 +68,7 @@ import org.apache.ambari.server.orm.dao.PermissionDAO;
import org.apache.ambari.server.orm.dao.PrincipalDAO;
import org.apache.ambari.server.orm.dao.PrivilegeDAO;
import org.apache.ambari.server.orm.dao.ResourceDAO;
+import org.apache.ambari.server.orm.dao.ResourceTypeDAO;
import org.apache.ambari.server.orm.dao.UserDAO;
import org.apache.ambari.server.orm.dao.ViewDAO;
import org.apache.ambari.server.orm.dao.ViewInstanceDAO;
@@ -539,7 +540,8 @@ public class AmbariServer {
ClusterPrivilegeResourceProvider.init(injector.getInstance(ClusterDAO.class));
ViewRegistry.init(injector.getInstance(ViewDAO.class), injector.getInstance(ViewInstanceDAO.class),
injector.getInstance(UserDAO.class), injector.getInstance(MemberDAO.class),
- injector.getInstance(PrivilegeDAO.class), injector.getInstance(SecurityHelper.class));
+ injector.getInstance(PrivilegeDAO.class), injector.getInstance(SecurityHelper.class),
+ injector.getInstance(ResourceDAO.class), injector.getInstance(ResourceTypeDAO.class));
}
/**
http://git-wip-us.apache.org/repos/asf/ambari/blob/1b72f6df/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PrivilegeResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PrivilegeResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PrivilegeResourceProvider.java
index 60d6396..d8fce4d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PrivilegeResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/PrivilegeResourceProvider.java
@@ -142,8 +142,9 @@ public abstract class PrivilegeResourceProvider<T> extends AbstractResourceProvi
* @param properties the set of properties
*
* @return the entities
+ * @throws AmbariException if resource entities were not found
*/
- public abstract Map<Long, T> getResourceEntities(Map<String, Object> properties);
+ public abstract Map<Long, T> getResourceEntities(Map<String, Object> properties) throws AmbariException;
/**
* Get the id for the resource specified by predicate.
@@ -183,7 +184,12 @@ public abstract class PrivilegeResourceProvider<T> extends AbstractResourceProvi
}
for (Map<String, Object> properties : propertyMaps) {
- Map<Long, T> resourceEntities = getResourceEntities(properties);
+ Map<Long, T> resourceEntities;
+ try {
+ resourceEntities = getResourceEntities(properties);
+ } catch (AmbariException e) {
+ throw new SystemException("Could not get resource list from request", e);
+ }
resourceIds.addAll(resourceEntities.keySet());
@@ -319,9 +325,7 @@ public abstract class PrivilegeResourceProvider<T> extends AbstractResourceProvi
PrivilegeEntity entity = new PrivilegeEntity();
String permissionName = (String) properties.get(PERMISSION_NAME_PROPERTY_ID);
ResourceEntity resourceEntity = resourceDAO.findById(resourceId);
-
PermissionEntity permission = getPermission(permissionName, resourceEntity);
-
if (permission == null) {
throw new AmbariException("Can't find a permission named " + permissionName +
" for the resource.");
@@ -331,7 +335,6 @@ public abstract class PrivilegeResourceProvider<T> extends AbstractResourceProvi
String principalName = (String) properties.get(PRINCIPAL_NAME_PROPERTY_ID);
String principalType = (String) properties.get(PRINCIPAL_TYPE_PROPERTY_ID);
-
if (PrincipalTypeEntity.GROUP_PRINCIPAL_TYPE_NAME.equalsIgnoreCase(principalType)) {
GroupEntity groupEntity = groupDAO.findGroupByName(principalName);
if (groupEntity != null) {
@@ -381,7 +384,6 @@ public abstract class PrivilegeResourceProvider<T> extends AbstractResourceProvi
throw new AmbariException("Can't grant " + entity.getPermission().getResourceType().getName() +
" permission on a " + entity.getResource().getResourceType().getName() + " resource.");
}
-
privilegeDAO.create(entity);
return null;
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/1b72f6df/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewPrivilegeResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewPrivilegeResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewPrivilegeResourceProvider.java
index 57eb28e..ea4acef 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewPrivilegeResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewPrivilegeResourceProvider.java
@@ -101,7 +101,7 @@ public class ViewPrivilegeResourceProvider extends PrivilegeResourceProvider<Vie
// ----- PrivilegeResourceProvider -----------------------------------------
@Override
- public Map<Long, ViewInstanceEntity> getResourceEntities(Map<String, Object> properties) {
+ public Map<Long, ViewInstanceEntity> getResourceEntities(Map<String, Object> properties) throws AmbariException {
ViewRegistry viewRegistry = ViewRegistry.getInstance();
String viewName = (String) properties.get(PRIVILEGE_VIEW_NAME_PROPERTY_ID);
@@ -112,6 +112,9 @@ public class ViewPrivilegeResourceProvider extends PrivilegeResourceProvider<Vie
ViewInstanceEntity viewInstanceEntity =
viewRegistry.getInstanceDefinition(viewName, viewVersion, instanceName);
+ if (viewInstanceEntity == null) {
+ throw new AmbariException("View instance " + instanceName + " of " + viewName + viewVersion + " was not found");
+ }
return Collections.singletonMap(viewInstanceEntity.getResource().getId(), viewInstanceEntity);
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/1b72f6df/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
index 2878dd6..3f1cd8f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
@@ -123,6 +123,13 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
private String icon64;
/**
+ * The XML driven instance flag.
+ */
+ @Column(name="xml_driven")
+ @Basic
+ private char xmlDriven = 'N';
+
+ /**
* The instance properties.
*/
@OneToMany(cascade = CascadeType.ALL, mappedBy = "viewInstance")
@@ -397,6 +404,24 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
}
/**
+ * Get the xml driven flag.
+ *
+ * @return the xml driven flag
+ */
+ public boolean isXmlDriven() {
+ return xmlDriven == 'y' || xmlDriven == 'Y';
+ }
+
+ /**
+ * Set the xml driven flag.
+ *
+ * @param xmlDriven the xml driven flag
+ */
+ public void setXmlDriven(boolean xmlDriven) {
+ this.xmlDriven = (xmlDriven) ? 'Y' : 'N';
+ }
+
+ /**
* Get the instance properties.
*
* @return the instance properties
http://git-wip-us.apache.org/repos/asf/ambari/blob/1b72f6df/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
index 9a0f4ca..bb248ba 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
@@ -191,6 +191,8 @@ public class UpgradeCatalog170 extends AbstractUpgradeCatalog {
Integer.class, 1, 1, false));
dbAccessor.addColumn("viewinstance", new DBColumnInfo("resource_id",
Long.class, 1, 1, false));
+ dbAccessor.addColumn("viewinstance", new DBColumnInfo("xml_driven",
+ Character.class, 1, null, true));
dbAccessor.addColumn("clusters", new DBColumnInfo("resource_id",
Long.class, 1, 1, false));
http://git-wip-us.apache.org/repos/asf/ambari/blob/1b72f6df/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
index 808de92..0acbb62 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
@@ -18,9 +18,31 @@
package org.apache.ambari.server.view;
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
+import java.beans.IntrospectionException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
import org.apache.ambari.server.api.resources.ResourceInstanceFactoryImpl;
import org.apache.ambari.server.api.resources.SubResourceDefinition;
@@ -31,6 +53,8 @@ import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.controller.spi.Resource;
import org.apache.ambari.server.orm.dao.MemberDAO;
import org.apache.ambari.server.orm.dao.PrivilegeDAO;
+import org.apache.ambari.server.orm.dao.ResourceDAO;
+import org.apache.ambari.server.orm.dao.ResourceTypeDAO;
import org.apache.ambari.server.orm.dao.UserDAO;
import org.apache.ambari.server.orm.dao.ViewDAO;
import org.apache.ambari.server.orm.dao.ViewInstanceDAO;
@@ -72,30 +96,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.GrantedAuthority;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Unmarshaller;
-
-import java.beans.IntrospectionException;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
/**
* Registry for view and view instance definitions.
@@ -178,6 +181,15 @@ public class ViewRegistry {
*/
private static SecurityHelper securityHelper;
+ /**
+ * Resource data access object.
+ */
+ private static ResourceDAO resourceDAO;
+
+ /**
+ * Resource type data access object.
+ */
+ private static ResourceTypeDAO resourceTypeDAO;
// ----- Constructors ------------------------------------------------------
@@ -388,13 +400,17 @@ public class ViewRegistry {
// extract the archive and get the class loader
ClassLoader cl = extractViewArchive(archiveFile, helper.getFile(archivePath));
+ viewConfig = helper.getViewConfigFromExtractedArchive(archivePath);
+
ViewEntity viewDefinition = createViewDefinition(viewConfig, configuration, cl, archivePath);
Set<ViewInstanceEntity> instanceDefinitions = new HashSet<ViewInstanceEntity>();
for (InstanceConfig instanceConfig : viewConfig.getInstances()) {
try {
- instanceDefinitions.add(createViewInstanceDefinition(viewConfig, viewDefinition, instanceConfig));
+ ViewInstanceEntity instanceEntity = createViewInstanceDefinition(viewConfig, viewDefinition, instanceConfig);
+ instanceEntity.setXmlDriven(true);
+ instanceDefinitions.add(instanceEntity);
} catch (Exception e) {
LOG.error("Caught exception adding view instance for view " +
viewDefinition.getViewName(), e);
@@ -451,9 +467,11 @@ public class ViewRegistry {
}
instanceEntity.validate(viewEntity);
+ ResourceTypeEntity resourceTypeEntity = resourceTypeDAO.findByName(ViewEntity.getViewName(viewName, version));
// create an admin resource to represent this view instance
ResourceEntity resourceEntity = new ResourceEntity();
- resourceEntity.setResourceType(viewEntity.getResourceType());
+ resourceEntity.setResourceType(resourceTypeEntity);
+ resourceDAO.create(resourceEntity);
instanceEntity.setResource(resourceEntity);
@@ -467,6 +485,7 @@ public class ViewRegistry {
throw new IllegalStateException(message);
}
instanceEntity.setViewInstanceId(persistedInstance.getViewInstanceId());
+ instanceEntity.setResource(persistedInstance.getResource());
try {
// bind the view instance to a view
@@ -507,6 +526,9 @@ public class ViewRegistry {
ViewInstanceEntity entity = getInstanceDefinition(viewName, version, instanceName);
if (entity != null) {
+ if (entity.isXmlDriven()) {
+ throw new IllegalStateException("View instances defined via xml can't be updated through api requests");
+ }
if (LOG.isDebugEnabled()) {
LOG.debug("Updating view instance " + viewName + "/" +
version + "/" + instanceName);
@@ -542,8 +564,9 @@ public class ViewRegistry {
* Uninstall a view instance for the view with the given view name.
*
* @param instanceEntity the view instance entity
+ * @throws IllegalStateException if the given instance is not in a valid state
*/
- public void uninstallViewInstance(ViewInstanceEntity instanceEntity) {
+ public void uninstallViewInstance(ViewInstanceEntity instanceEntity) throws IllegalStateException {
ViewEntity viewEntity = getDefinition(instanceEntity.getViewName());
if (viewEntity != null) {
@@ -552,7 +575,9 @@ public class ViewRegistry {
String version = viewEntity.getVersion();
if (getInstanceDefinition(viewName, version, instanceName) != null) {
-
+ if (instanceEntity.isXmlDriven()) {
+ throw new IllegalStateException("View instances defined via xml can't be deleted through api requests");
+ }
if (LOG.isDebugEnabled()) {
LOG.debug("Deleting view instance " + viewName + "/" +
version + "/" +instanceName);
@@ -882,10 +907,6 @@ public class ViewRegistry {
setPersistenceEntities(viewInstanceDefinition);
- ResourceEntity resourceEntity = new ResourceEntity();
- resourceEntity.setResourceType(viewDefinition.getResourceType());
- viewInstanceDefinition.setResource(resourceEntity);
-
viewDefinition.addInstanceDefinition(viewInstanceDefinition);
}
@@ -983,13 +1004,28 @@ public class ViewRegistry {
}
}
- // sync the given view with the db
+ /**
+ * Sync given view with data in DB. Ensures that view data in DB is updated,
+ * all instances changes from xml config are reflected to DB
+ *
+ * @param view view config from xml
+ * @param instanceDefinitions view instances from xml
+ * @throws Exception
+ */
private void syncView(ViewEntity view,
Set<ViewInstanceEntity> instanceDefinitions)
throws Exception {
-
String viewName = view.getName();
+ // get or create an admin resource type to represent this view
+ ResourceTypeEntity resourceTypeEntity = resourceTypeDAO.findByName(viewName);
+ if (resourceTypeEntity == null) {
+ resourceTypeEntity = new ResourceTypeEntity();
+ resourceTypeEntity.setName(view.getName());
+ resourceTypeDAO.create(resourceTypeEntity);
+ }
+ view.setResourceType(resourceTypeEntity);
+
ViewEntity persistedView = viewDAO.findByName(viewName);
// if the view is not yet persisted ...
@@ -997,13 +1033,31 @@ public class ViewRegistry {
if (LOG.isDebugEnabled()) {
LOG.debug("Creating View " + viewName + ".");
}
+
+ for( ViewInstanceEntity instance : view.getInstances()) {
+
+ // create an admin resource to represent this view instance
+ ResourceEntity resourceEntity = new ResourceEntity();
+ resourceEntity.setResourceType(resourceTypeEntity);
+ resourceDAO.create(resourceEntity);
+
+ instance.setResource(resourceEntity);
+ }
// ... merge it
- persistedView = viewDAO.merge(view);
+ viewDAO.merge(view);
+
+ persistedView = viewDAO.findByName(viewName);
+ if (persistedView == null) {
+ String message = "View " + viewName + " can not be found.";
+
+ LOG.error(message);
+ throw new IllegalStateException(message);
+ }
}
- Map<String, ViewInstanceEntity> instanceEntityMap = new HashMap<String, ViewInstanceEntity>();
+ Map<String, ViewInstanceEntity> xmlInstanceEntityMap = new HashMap<String, ViewInstanceEntity>();
for( ViewInstanceEntity instance : view.getInstances()) {
- instanceEntityMap.put(instance.getName(), instance);
+ xmlInstanceEntityMap.put(instance.getName(), instance);
}
view.setResourceType(persistedView.getResourceType());
@@ -1016,7 +1070,12 @@ public class ViewRegistry {
ViewInstanceEntity instance =
view.getInstanceDefinition(instanceName);
- instanceEntityMap.remove(instanceName);
+ if (persistedInstance.isXmlDriven() && !xmlInstanceEntityMap.containsKey(instanceName)) {
+ instanceDAO.remove(persistedInstance);
+ xmlInstanceEntityMap.remove(instanceName);
+ continue;
+ }
+ xmlInstanceEntityMap.remove(instanceName);
// if the persisted instance is not in the registry ...
if (instance == null) {
@@ -1027,23 +1086,39 @@ public class ViewRegistry {
}
instance.setViewInstanceId(persistedInstance.getViewInstanceId());
- // apply the persisted overrides to the in-memory instance
- instance.setLabel(persistedInstance.getLabel());
- instance.setDescription(persistedInstance.getDescription());
- instance.setVisible(persistedInstance.isVisible());
- instance.setData(persistedInstance.getData());
- instance.setProperties(persistedInstance.getProperties());
- instance.setEntities(persistedInstance.getEntities());
+ if (instance.isXmlDriven()) {
+ // override db data with data from {@InstanceConfig}
+ persistedInstance.setLabel(instance.getLabel());
+ persistedInstance.setDescription(instance.getDescription());
+ persistedInstance.setVisible(instance.isVisible());
+ persistedInstance.setIcon(instance.getIcon());
+ persistedInstance.setIcon64(instance.getIcon64());
+ persistedInstance.setProperties(instance.getProperties());
+
+ instanceDAO.merge(persistedInstance);
+ } else {
+ // apply the persisted overrides to the in-memory instance
+ view.removeInstanceDefinition(instanceName);
+ view.addInstanceDefinition(persistedInstance);
+ }
instance.setResource(persistedInstance.getResource());
}
- // these instances appear in the archive but have been deleted
- // from the db... remove them from the registry
- for (ViewInstanceEntity instance : instanceEntityMap.values()) {
- view.removeInstanceDefinition(instance.getName());
- instanceDefinitions.remove(instance);
+ // these instances appear in the archive but not present in the db... add
+ // them to db and registry
+ for (ViewInstanceEntity instance : xmlInstanceEntityMap.values()) {
+ // create an admin resource to represent this view instance
+ ResourceEntity resourceEntity = new ResourceEntity();
+ resourceEntity.setResourceType(resourceTypeEntity);
+ resourceDAO.create(resourceEntity);
+ instance.setResource(resourceEntity);
+
+ instanceDAO.merge(instance);
+ bindViewInstance(view, instance);
+ instanceDefinitions.add(instance);
}
+
}
// ensure that the extracted view archive directory exists
@@ -1196,13 +1271,16 @@ public class ViewRegistry {
*/
public static void init(ViewDAO viewDAO, ViewInstanceDAO instanceDAO,
UserDAO userDAO, MemberDAO memberDAO, PrivilegeDAO privilegeDAO,
- SecurityHelper securityHelper) {
+ SecurityHelper securityHelper, ResourceDAO resourceDAO,
+ ResourceTypeDAO resourceTypeDAO) {
setViewDAO(viewDAO);
setInstanceDAO(instanceDAO);
setUserDAO(userDAO);
setMemberDAO(memberDAO);
setPrivilegeDAO(privilegeDAO);
setSecurityHelper(securityHelper);
+ setResourceDAO(resourceDAO);
+ setResourceTypeDAO(resourceTypeDAO);
}
/**
@@ -1259,6 +1337,24 @@ public class ViewRegistry {
ViewRegistry.securityHelper = securityHelper;
}
+ /**
+ * Set the resource DAO.
+ *
+ * @param resourceDAO the resource DAO
+ */
+ protected static void setResourceDAO(ResourceDAO resourceDAO) {
+ ViewRegistry.resourceDAO = resourceDAO;
+ }
+
+ /**
+ * Set the resource type DAO.
+ *
+ * @param resourceTypeDAO the resource type DAO.
+ */
+ protected static void setResourceTypeDAO(ResourceTypeDAO resourceTypeDAO) {
+ ViewRegistry.resourceTypeDAO = resourceTypeDAO;
+ }
+
// ----- inner class : ViewRegistryHelper ----------------------------------
@@ -1286,6 +1382,26 @@ public class ViewRegistry {
}
/**
+ * Get the view configuration from the extracted archive file.
+ *
+ * @param archivePath path to extracted archive
+ *
+ * @return the associated view configuration
+ *
+ * @throws JAXBException if xml is malformed
+ * @throws FileNotFoundException if xml was not found
+ */
+ public ViewConfig getViewConfigFromExtractedArchive(String archivePath)
+ throws JAXBException, FileNotFoundException {
+
+ InputStream configStream = new FileInputStream(new File(archivePath + File.separator + VIEW_XML));
+ JAXBContext jaxbContext = JAXBContext.newInstance(ViewConfig.class);
+ Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
+
+ return (ViewConfig) jaxbUnmarshaller.unmarshal(configStream);
+ }
+
+ /**
* Get a new file instance for the given path.
*
* @param path the path
http://git-wip-us.apache.org/repos/asf/ambari/blob/1b72f6df/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
index b4c7fb6..ff6c8c0 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -69,7 +69,7 @@ CREATE TABLE blueprint_configuration (blueprint_name VARCHAR(255) NOT NULL, type
CREATE TABLE hostgroup_configuration (blueprint_name VARCHAR(255) NOT NULL, hostgroup_name VARCHAR(255) NOT NULL, type_name VARCHAR(255) NOT NULL, config_data TEXT NOT NULL, config_attributes TEXT, PRIMARY KEY(blueprint_name, hostgroup_name, type_name));
CREATE TABLE viewmain (view_name VARCHAR(255) NOT NULL, label VARCHAR(255), version VARCHAR(255), resource_type_id INTEGER NOT NULL, icon VARCHAR(255), icon64 VARCHAR(255), archive VARCHAR(255), mask VARCHAR(255), PRIMARY KEY(view_name));
CREATE TABLE viewinstancedata (view_instance_id BIGINT, view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, user_name VARCHAR(255) NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(VIEW_INSTANCE_ID, NAME, USER_NAME));
-CREATE TABLE viewinstance (view_instance_id BIGINT, resource_id BIGINT NOT NULL, view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255), description VARCHAR(255), visible CHAR(1), icon VARCHAR(255), icon64 VARCHAR(255), PRIMARY KEY(view_instance_id));
+CREATE TABLE viewinstance (view_instance_id BIGINT, resource_id BIGINT NOT NULL, view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255), description VARCHAR(255), visible CHAR(1), icon VARCHAR(255), icon64 VARCHAR(255), xml_driven CHAR(1), PRIMARY KEY(view_instance_id));
CREATE TABLE viewinstanceproperty (view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(view_name, view_instance_name, name));
CREATE TABLE viewparameter (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255), required CHAR(1), masked CHAR(1), PRIMARY KEY(view_name, name));
CREATE TABLE viewresource (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, plural_name VARCHAR(255), id_property VARCHAR(255), subResource_names VARCHAR(255), provider VARCHAR(255), service VARCHAR(255), resource VARCHAR(255), PRIMARY KEY(view_name, name));
http://git-wip-us.apache.org/repos/asf/ambari/blob/1b72f6df/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
index 87d0fd9..bdb20b8 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -60,7 +60,7 @@ CREATE TABLE blueprint_configuration (blueprint_name VARCHAR2(255) NOT NULL, typ
CREATE TABLE hostgroup_configuration (blueprint_name VARCHAR2(255) NOT NULL, hostgroup_name VARCHAR2(255) NOT NULL, type_name VARCHAR2(255) NOT NULL, config_data CLOB NOT NULL, config_attributes CLOB, PRIMARY KEY(blueprint_name, hostgroup_name, type_name));
CREATE TABLE viewmain (view_name VARCHAR(255) NOT NULL, label VARCHAR(255), version VARCHAR(255), resource_type_id NUMBER(10) NOT NULL, icon VARCHAR(255), icon64 VARCHAR(255), archive VARCHAR(255), mask VARCHAR(255), PRIMARY KEY(view_name));
CREATE TABLE viewinstancedata (view_instance_id NUMBER(19), view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, user_name VARCHAR(255) NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(view_instance_id, name, user_name));
-CREATE TABLE viewinstance (view_instance_id NUMBER(19), resource_id NUMBER(19) NOT NULL, view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255), description VARCHAR(255), visible CHAR(1), icon VARCHAR(255), icon64 VARCHAR(255), PRIMARY KEY(view_instance_id));
+CREATE TABLE viewinstance (view_instance_id NUMBER(19), resource_id NUMBER(19) NOT NULL, view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255), description VARCHAR(255), visible CHAR(1), icon VARCHAR(255), icon64 VARCHAR(255), xml_driven CHAR(1), PRIMARY KEY(view_instance_id));
CREATE TABLE viewinstanceproperty (view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(view_name, view_instance_name, name));
CREATE TABLE viewparameter (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255), required CHAR(1), masked CHAR(1), PRIMARY KEY(view_name, name));
CREATE TABLE viewresource (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, plural_name VARCHAR(255), id_property VARCHAR(255), subResource_names VARCHAR(255), provider VARCHAR(255), service VARCHAR(255), "resource" VARCHAR(255), PRIMARY KEY(view_name, name));
http://git-wip-us.apache.org/repos/asf/ambari/blob/1b72f6df/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
index bec8fd9..1f3b3e5 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -97,7 +97,7 @@ CREATE TABLE hostgroup_configuration (blueprint_name VARCHAR(255) NOT NULL, host
CREATE TABLE viewmain (view_name VARCHAR(255) NOT NULL, label VARCHAR(255), version VARCHAR(255), resource_type_id INTEGER NOT NULL, icon VARCHAR(255), icon64 VARCHAR(255), archive VARCHAR(255), mask VARCHAR(255), PRIMARY KEY(view_name));
CREATE TABLE viewinstancedata (view_instance_id BIGINT, view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, user_name VARCHAR(255) NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(view_instance_id, name, user_name));
-CREATE TABLE viewinstance (view_instance_id BIGINT, resource_id BIGINT NOT NULL, view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255), description VARCHAR(255), visible CHAR(1), icon VARCHAR(255), icon64 VARCHAR(255), PRIMARY KEY(view_instance_id));
+CREATE TABLE viewinstance (view_instance_id BIGINT, resource_id BIGINT NOT NULL, view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255), description VARCHAR(255), visible CHAR(1), icon VARCHAR(255), icon64 VARCHAR(255), xml_driven CHAR(1), PRIMARY KEY(view_instance_id));
CREATE TABLE viewinstanceproperty (view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(view_name, view_instance_name, name));
CREATE TABLE viewparameter (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255), required CHAR(1), masked CHAR(1), PRIMARY KEY(view_name, name));
CREATE TABLE viewresource (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, plural_name VARCHAR(255), id_property VARCHAR(255), subResource_names VARCHAR(255), provider VARCHAR(255), service VARCHAR(255), resource VARCHAR(255), PRIMARY KEY(view_name, name));
http://git-wip-us.apache.org/repos/asf/ambari/blob/1b72f6df/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
index 0dd33af..58ad54a 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
@@ -149,7 +149,7 @@ GRANT ALL PRIVILEGES ON TABLE ambari.hostgroup_configuration TO :username;
CREATE TABLE ambari.viewmain (view_name VARCHAR(255) NOT NULL, label VARCHAR(255), version VARCHAR(255), resource_type_id INTEGER NOT NULL, icon VARCHAR(255), icon64 VARCHAR(255), archive VARCHAR(255), mask VARCHAR(255), PRIMARY KEY(view_name));
CREATE TABLE ambari.viewinstancedata (view_instance_id BIGINT, view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, user_name VARCHAR(255) NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(view_instance_id, name, user_name));
-CREATE TABLE ambari.viewinstance (view_instance_id BIGINT, resource_id BIGINT NOT NULL, view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255), description VARCHAR(255), visible CHAR(1), icon VARCHAR(255), icon64 VARCHAR(255), PRIMARY KEY(view_instance_id));
+CREATE TABLE ambari.viewinstance (view_instance_id BIGINT, resource_id BIGINT NOT NULL, view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255), description VARCHAR(255), visible CHAR(1), icon VARCHAR(255), icon64 VARCHAR(255), xml_driven CHAR(1), PRIMARY KEY(view_instance_id));
CREATE TABLE ambari.viewinstanceproperty (view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(view_name, view_instance_name, name));
CREATE TABLE ambari.viewparameter (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255), required CHAR(1), masked CHAR(1), PRIMARY KEY(view_name, name));
CREATE TABLE ambari.viewresource (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, plural_name VARCHAR(255), id_property VARCHAR(255), subResource_names VARCHAR(255), provider VARCHAR(255), service VARCHAR(255), resource VARCHAR(255), PRIMARY KEY(view_name, name));
http://git-wip-us.apache.org/repos/asf/ambari/blob/1b72f6df/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
index 5396eec..5a95ee8 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
@@ -24,6 +24,8 @@ import org.apache.ambari.server.controller.spi.Resource;
import org.apache.ambari.server.controller.spi.ResourceProvider;
import org.apache.ambari.server.orm.dao.MemberDAO;
import org.apache.ambari.server.orm.dao.PrivilegeDAO;
+import org.apache.ambari.server.orm.dao.ResourceDAO;
+import org.apache.ambari.server.orm.dao.ResourceTypeDAO;
import org.apache.ambari.server.orm.dao.UserDAO;
import org.apache.ambari.server.orm.dao.ViewDAO;
import org.apache.ambari.server.orm.dao.ViewInstanceDAO;
@@ -46,13 +48,14 @@ import org.apache.ambari.server.view.events.EventImpl;
import org.apache.ambari.server.view.events.EventImplTest;
import org.apache.ambari.view.events.Event;
import org.apache.ambari.view.events.Listener;
-import org.easymock.Capture;
+import org.easymock.EasyMock;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import javax.xml.bind.JAXBException;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@@ -70,7 +73,6 @@ import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
-import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.expect;
@@ -165,8 +167,14 @@ public class ViewRegistryTest {
resourceTypeEntity.setName("MY_VIEW{1.0.0}");
ViewDAO vDAO = createMock(ViewDAO.class);
+ ResourceDAO rDAO = createNiceMock(ResourceDAO.class);
+ ResourceTypeDAO rtDAO = createNiceMock(ResourceTypeDAO.class);
+ ViewInstanceDAO viDAO = createNiceMock(ViewInstanceDAO.class);
ViewRegistry.setViewDAO(vDAO);
+ ViewRegistry.setResourceDAO(rDAO);
+ ViewRegistry.setResourceTypeDAO(rtDAO);
+ ViewRegistry.setInstanceDAO(viDAO);
ViewEntity viewDefinition = ViewEntityTest.getViewEntity();
viewDefinition.setResourceType(resourceTypeEntity);
@@ -206,6 +214,7 @@ public class ViewRegistryTest {
expect(viewDir.listFiles()).andReturn(new File[]{viewArchive});
expect(viewArchive.isDirectory()).andReturn(false);
+ expect(viewArchive.getAbsolutePath()).andReturn("/var/lib/ambari-server/resources/views/work/MY_VIEW{1.0.0}").anyTimes();
expect(archiveDir.exists()).andReturn(false);
expect(archiveDir.getAbsolutePath()).andReturn(
@@ -243,16 +252,19 @@ public class ViewRegistryTest {
expect(libDir.listFiles()).andReturn(new File[]{fileEntry});
expect(fileEntry.toURI()).andReturn(new URI("file:./"));
- Capture<ViewEntity> captureViewEntity = new Capture<ViewEntity>();
-
- expect(vDAO.findByName("MY_VIEW{1.0.0}")).andReturn(null);
- expect(vDAO.merge(capture(captureViewEntity))).andReturn(viewDefinition);
+ expect(vDAO.findByName("MY_VIEW{1.0.0}")).andReturn(viewDefinition);
expect(vDAO.findAll()).andReturn(Collections.<ViewEntity>emptyList());
+ expect(rtDAO.findByName("MY_VIEW{1.0.0}")).andReturn(null);
+ rtDAO.create(EasyMock.anyObject(ResourceTypeEntity.class));
+ EasyMock.expectLastCall().anyTimes();
+
+ expect(viDAO.merge(EasyMock.anyObject(ViewInstanceEntity.class))).andReturn(null).times(2);
+
// replay mocks
replay(configuration, viewDir, extractedArchiveDir, viewArchive, archiveDir, entryFile, classesDir,
- libDir, fileEntry, viewJarFile, enumeration, jarEntry, is, fos, vDAO);
+ libDir, fileEntry, viewJarFile, enumeration, jarEntry, is, fos, rDAO, rtDAO, vDAO, viDAO);
ViewRegistry registry = ViewRegistry.getInstance();
registry.setHelper(new TestViewRegistryHelper(viewConfigs, files, outputStreams, jarFiles));
@@ -260,11 +272,10 @@ public class ViewRegistryTest {
Set<ViewInstanceEntity> instanceEntities = registry.readViewArchives(configuration);
Assert.assertEquals(2, instanceEntities.size());
- Assert.assertEquals("MY_VIEW", captureViewEntity.getValue().getCommonName());
// verify mocks
verify(configuration, viewDir, extractedArchiveDir, viewArchive, archiveDir, entryFile, classesDir,
- libDir, fileEntry, viewJarFile, enumeration, jarEntry, is, fos, vDAO);
+ libDir, fileEntry, viewJarFile, enumeration, jarEntry, is, fos, rDAO, rtDAO, vDAO, viDAO);
}
@Test
@@ -331,6 +342,7 @@ public class ViewRegistryTest {
expect(viewDir.listFiles()).andReturn(new File[]{viewArchive});
expect(viewArchive.isDirectory()).andReturn(false);
+ expect(viewArchive.getAbsolutePath()).andReturn("/var/lib/ambari-server/resources/views/work/MY_VIEW{1.0.0}");
expect(archiveDir.exists()).andReturn(false);
expect(archiveDir.getAbsolutePath()).andReturn(
@@ -368,11 +380,6 @@ public class ViewRegistryTest {
expect(libDir.listFiles()).andReturn(new File[]{fileEntry});
expect(fileEntry.toURI()).andReturn(new URI("file:./"));
- Capture<ViewEntity> captureViewEntity = new Capture<ViewEntity>();
-
- expect(vDAO.findByName("MY_VIEW{1.0.0}")).andReturn(null);
- expect(vDAO.merge(capture(captureViewEntity))).andThrow(new IllegalArgumentException("Expected exception."));
-
expect(vDAO.findAll()).andReturn(Collections.<ViewEntity>emptyList());
// replay mocks
@@ -508,8 +515,10 @@ public class ViewRegistryTest {
MemberDAO memberDAO = createNiceMock(MemberDAO.class);
PrivilegeDAO privilegeDAO = createNiceMock(PrivilegeDAO.class);
SecurityHelper securityHelper = createNiceMock(SecurityHelper.class);
+ ResourceDAO rDAO = createNiceMock(ResourceDAO.class);
+ ResourceTypeDAO rtDAO = createNiceMock(ResourceTypeDAO.class);
- ViewRegistry.init(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO, securityHelper);
+ ViewRegistry.init(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO, securityHelper, rDAO, rtDAO);
ViewRegistry registry = ViewRegistry.getInstance();
@@ -548,8 +557,10 @@ public class ViewRegistryTest {
MemberDAO memberDAO = createNiceMock(MemberDAO.class);
PrivilegeDAO privilegeDAO = createNiceMock(PrivilegeDAO.class);
SecurityHelper securityHelper = createNiceMock(SecurityHelper.class);
+ ResourceDAO rDAO = createNiceMock(ResourceDAO.class);
+ ResourceTypeDAO rtDAO = createNiceMock(ResourceTypeDAO.class);
- ViewRegistry.init(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO, securityHelper);
+ ViewRegistry.init(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO, securityHelper, rDAO, rtDAO);
ViewRegistry registry = ViewRegistry.getInstance();
@@ -583,8 +594,10 @@ public class ViewRegistryTest {
MemberDAO memberDAO = createNiceMock(MemberDAO.class);
PrivilegeDAO privilegeDAO = createNiceMock(PrivilegeDAO.class);
SecurityHelper securityHelper = createNiceMock(SecurityHelper.class);
+ ResourceDAO rDAO = createNiceMock(ResourceDAO.class);
+ ResourceTypeDAO rtDAO = createNiceMock(ResourceTypeDAO.class);
- ViewRegistry.init(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO, securityHelper);
+ ViewRegistry.init(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO, securityHelper, rDAO, rtDAO);
ViewRegistry registry = ViewRegistry.getInstance();
@@ -619,8 +632,10 @@ public class ViewRegistryTest {
MemberDAO memberDAO = createNiceMock(MemberDAO.class);
PrivilegeDAO privilegeDAO = createNiceMock(PrivilegeDAO.class);
SecurityHelper securityHelper = createNiceMock(SecurityHelper.class);
+ ResourceDAO rDAO = createNiceMock(ResourceDAO.class);
+ ResourceTypeDAO rtDAO = createNiceMock(ResourceTypeDAO.class);
- ViewRegistry.init(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO, securityHelper);
+ ViewRegistry.init(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO, securityHelper, rDAO, rtDAO);
ViewRegistry registry = ViewRegistry.getInstance();
@@ -663,8 +678,10 @@ public class ViewRegistryTest {
MemberDAO memberDAO = createNiceMock(MemberDAO.class);
PrivilegeDAO privilegeDAO = createNiceMock(PrivilegeDAO.class);
SecurityHelper securityHelper = createNiceMock(SecurityHelper.class);
+ ResourceDAO rDAO = createNiceMock(ResourceDAO.class);
+ ResourceTypeDAO rtDAO = createNiceMock(ResourceTypeDAO.class);
- ViewRegistry.init(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO, securityHelper);
+ ViewRegistry.init(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO, securityHelper, rDAO, rtDAO);
ViewRegistry registry = ViewRegistry.getInstance();
@@ -705,8 +722,10 @@ public class ViewRegistryTest {
MemberDAO memberDAO = createNiceMock(MemberDAO.class);
PrivilegeDAO privilegeDAO = createNiceMock(PrivilegeDAO.class);
SecurityHelper securityHelper = createNiceMock(SecurityHelper.class);
+ ResourceDAO rDAO = createNiceMock(ResourceDAO.class);
+ ResourceTypeDAO rtDAO = createNiceMock(ResourceTypeDAO.class);
- ViewRegistry.init(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO, securityHelper);
+ ViewRegistry.init(viewDAO, viewInstanceDAO, userDAO, memberDAO, privilegeDAO, securityHelper, rDAO, rtDAO);
ViewRegistry registry = ViewRegistry.getInstance();
@@ -760,6 +779,16 @@ public class ViewRegistryTest {
return viewConfigs.get(archiveFile);
}
+ public ViewConfig getViewConfigFromExtractedArchive(String archivePath)
+ throws JAXBException, FileNotFoundException {
+ for (File viewConfigKey: viewConfigs.keySet()) {
+ if (viewConfigKey.getAbsolutePath().equals(archivePath)) {
+ return viewConfigs.get(viewConfigKey);
+ }
+ }
+ return null;
+ }
+
@Override
public File getFile(String path) {
return files.get(path);
[6/6] git commit: AMBARI-6853 - Alerts: Calculate Hash Based On Alert
Definitions (jonathanhurley)
Posted by jo...@apache.org.
AMBARI-6853 - Alerts: Calculate Hash Based On Alert Definitions (jonathanhurley)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/84b988bc
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/84b988bc
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/84b988bc
Branch: refs/heads/branch-alerts-dev
Commit: 84b988bcb4a6d127a1bb0a284e34f157ccf78fce
Parents: 1b72f6d
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Wed Aug 13 15:39:35 2014 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
Committed: Wed Aug 13 16:00:08 2014 -0400
----------------------------------------------------------------------
.../ambari/server/agent/HeartBeatHandler.java | 93 ++++---
.../ambari/server/agent/HeartBeatResponse.java | 54 ++--
.../AlertDefinitionResourceProvider.java | 139 +++++-----
.../server/orm/dao/AlertDefinitionDAO.java | 129 ++++++++-
.../orm/entities/AlertDefinitionEntity.java | 9 +-
.../server/state/alert/AlertDefinitionHash.java | 272 +++++++++++++++++++
.../src/main/resources/properties.json | 3 +-
.../AlertDefinitionResourceProviderTest.java | 134 ++++-----
.../server/orm/dao/AlertDefinitionDAOTest.java | 117 +++++++-
.../state/alerts/AlertDefinitionHashTest.java | 224 +++++++++++++++
10 files changed, 969 insertions(+), 205 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/84b988bc/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
index fa633c1..8a818a6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
@@ -17,20 +17,16 @@
*/
package org.apache.ambari.server.agent;
-import com.google.gson.Gson;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import com.google.inject.Singleton;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
+
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.HostNotFoundException;
import org.apache.ambari.server.RoleCommand;
@@ -46,7 +42,6 @@ import org.apache.ambari.server.controller.MaintenanceStateHelper;
import org.apache.ambari.server.metadata.ActionMetadata;
import org.apache.ambari.server.state.AgentVersion;
import org.apache.ambari.server.state.Alert;
-import org.apache.ambari.server.state.AlertState;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.state.ComponentInfo;
@@ -63,6 +58,7 @@ import org.apache.ambari.server.state.ServiceInfo;
import org.apache.ambari.server.state.StackId;
import org.apache.ambari.server.state.StackInfo;
import org.apache.ambari.server.state.State;
+import org.apache.ambari.server.state.alert.AlertDefinitionHash;
import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
import org.apache.ambari.server.state.host.HostHealthyHeartbeatEvent;
import org.apache.ambari.server.state.host.HostRegistrationRequestEvent;
@@ -78,6 +74,11 @@ import org.apache.ambari.server.utils.VersionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import com.google.gson.Gson;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Singleton;
+
/**
* This class handles the heartbeats coming from the agent, passes on the information
@@ -90,29 +91,40 @@ public class HeartBeatHandler {
private final Clusters clusterFsm;
private final ActionQueue actionQueue;
private final ActionManager actionManager;
+ private HeartbeatMonitor heartbeatMonitor;
+
@Inject
- Injector injector;
+ private Injector injector;
+
@Inject
- Configuration config;
+ private Configuration config;
+
@Inject
- AmbariMetaInfo ambariMetaInfo;
+ private AmbariMetaInfo ambariMetaInfo;
+
@Inject
- ActionMetadata actionMetadata;
- private HeartbeatMonitor heartbeatMonitor;
+ private ActionMetadata actionMetadata;
+
@Inject
private Gson gson;
+
@Inject
- ConfigHelper configHelper;
+ private ConfigHelper configHelper;
+
+ @Inject
+ private AlertDefinitionHash alertDefinitionHash;
+
private Map<String, Long> hostResponseIds = new ConcurrentHashMap<String, Long>();
+
private Map<String, HeartBeatResponse> hostResponses = new ConcurrentHashMap<String, HeartBeatResponse>();
@Inject
public HeartBeatHandler(Clusters fsm, ActionQueue aq, ActionManager am,
Injector injector) {
- this.clusterFsm = fsm;
- this.actionQueue = aq;
- this.actionManager = am;
- this.heartbeatMonitor = new HeartbeatMonitor(fsm, aq, am, 60000, injector);
+ clusterFsm = fsm;
+ actionQueue = aq;
+ actionManager = am;
+ heartbeatMonitor = new HeartbeatMonitor(fsm, aq, am, 60000, injector);
injector.injectMembers(this);
}
@@ -130,14 +142,17 @@ public class HeartBeatHandler {
if(heartbeat.getAgentEnv() != null && heartbeat.getAgentEnv().getHostHealth() != null) {
heartbeat.getAgentEnv().getHostHealth().setServerTimeStampAtReporting(now);
}
+
String hostname = heartbeat.getHostname();
Long currentResponseId = hostResponseIds.get(hostname);
HeartBeatResponse response;
+
if (currentResponseId == null) {
//Server restarted, or unknown host.
LOG.error("CurrentResponseId unknown for " + hostname + " - send register command");
return createRegisterCommand();
}
+
LOG.debug("Received heartbeat from host"
+ ", hostname=" + hostname
+ ", currentResponseId=" + currentResponseId
@@ -195,18 +210,23 @@ public class HeartBeatHandler {
// Examine heartbeart for component live status reports
processStatusReports(heartbeat, hostname, clusterFsm);
-
+
// Calculate host status
// NOTE: This step must be after processing command/status reports
processHostStatus(heartbeat, hostname);
-
+
calculateHostAlerts(heartbeat, hostname);
// Send commands if node is active
if (hostObject.getState().equals(HostState.HEALTHY)) {
sendCommands(hostname, response);
annotateResponse(hostname, response);
- }
+ }
+
+ // send the alert definition hash for this host
+ Map<String, String> alertDefinitionHashes = alertDefinitionHash.getHashes(hostname);
+ response.setAlertDefinitionHash(alertDefinitionHashes);
+
return response;
}
@@ -218,7 +238,7 @@ public class HeartBeatHandler {
}
}
}
-
+
protected void processHostStatus(HeartBeat heartbeat, String hostname) throws AmbariException {
Host host = clusterFsm.getHost(hostname);
@@ -268,7 +288,7 @@ public class HeartBeatHandler {
StackId stackId;
Cluster cluster = clusterFsm.getCluster(clusterName);
stackId = cluster.getDesiredStackVersion();
-
+
MaintenanceStateHelper psh = injector.getInstance(MaintenanceStateHelper.class);
List<ServiceComponentHost> scHosts = cluster.getServiceComponentHosts(heartbeat.getHostname());
@@ -347,7 +367,7 @@ public class HeartBeatHandler {
"STOP".equals(report.getCustomCommand())))) {
continue;
}
-
+
Cluster cl = clusterFsm.getCluster(report.getClusterName());
String service = report.getServiceName();
if (service == null || service.isEmpty()) {
@@ -439,7 +459,7 @@ public class HeartBeatHandler {
if (status.getClusterName().equals(cl.getClusterName())) {
try {
Service svc = cl.getService(status.getServiceName());
-
+
String componentName = status.getComponentName();
if (svc.getServiceComponents().containsKey(componentName)) {
ServiceComponent svcComp = svc.getServiceComponent(
@@ -470,7 +490,7 @@ public class HeartBeatHandler {
if (null != status.getConfigTags()) {
scHost.updateActualConfigs(status.getConfigTags());
}
-
+
Map<String, Object> extra = status.getExtra();
if (null != extra && !extra.isEmpty()) {
try {
@@ -479,7 +499,7 @@ public class HeartBeatHandler {
List<Map<String, String>> list = (List<Map<String, String>>) extra.get("processes");
scHost.setProcesses(list);
}
-
+
} catch (Exception e) {
LOG.error("Could not access extra JSON for " +
scHost.getServiceComponentName() + " from " +
@@ -487,7 +507,7 @@ public class HeartBeatHandler {
" (" + e.getMessage() + ")");
}
}
-
+
if (null != status.getAlerts()) {
List<Alert> clusterAlerts = new ArrayList<Alert>();
for (AgentAlert aa : status.getAlerts()) {
@@ -496,14 +516,15 @@ public class HeartBeatHandler {
scHost.getHostName(), aa.getState());
alert.setLabel(aa.getLabel());
alert.setText(aa.getText());
-
+
clusterAlerts.add(alert);
}
-
- if (0 != clusterAlerts.size())
- cl.addAlerts(clusterAlerts);
+
+ if (0 != clusterAlerts.size()) {
+ cl.addAlerts(clusterAlerts);
}
-
+ }
+
} else {
// TODO: What should be done otherwise?
@@ -563,7 +584,7 @@ public class HeartBeatHandler {
throw new AmbariException("Could not get jaxb string for command", e);
}
switch (ac.getCommandType()) {
- case BACKGROUND_EXECUTION_COMMAND:
+ case BACKGROUND_EXECUTION_COMMAND:
case EXECUTION_COMMAND: {
response.addExecutionCommand((ExecutionCommand) ac);
break;
@@ -699,7 +720,7 @@ public class HeartBeatHandler {
* @throws org.apache.ambari.server.AmbariException
*/
private void annotateResponse(String hostname, HeartBeatResponse response) throws AmbariException {
- for (Cluster cl : this.clusterFsm.getClustersForHost(hostname)) {
+ for (Cluster cl : clusterFsm.getClustersForHost(hostname)) {
List<ServiceComponentHost> scHosts = cl.getServiceComponentHosts(hostname);
if (scHosts != null && scHosts.size() > 0) {
response.setHasMappedComponents(true);
@@ -718,19 +739,19 @@ public class HeartBeatHandler {
throws AmbariException {
ComponentsResponse response = new ComponentsResponse();
- Cluster cluster = this.clusterFsm.getCluster(clusterName);
+ Cluster cluster = clusterFsm.getCluster(clusterName);
StackId stackId = cluster.getCurrentStackVersion();
if (stackId == null) {
throw new AmbariException("Cannot provide stack components map. " +
"Stack hasn't been selected yet.");
}
- StackInfo stack = this.ambariMetaInfo.getStackInfo(stackId.getStackName(),
+ StackInfo stack = ambariMetaInfo.getStackInfo(stackId.getStackName(),
stackId.getStackVersion());
response.setClusterName(clusterName);
response.setStackName(stackId.getStackName());
response.setStackVersion(stackId.getStackVersion());
- response.setComponents(this.getComponentsMap(stack));
+ response.setComponents(getComponentsMap(stack));
return response;
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/84b988bc/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatResponse.java
index 1670beb..24bd8a2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatResponse.java
@@ -20,26 +20,34 @@ package org.apache.ambari.server.agent;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import org.codehaus.jackson.annotate.JsonProperty;
/**
- *
* Controller to Agent response data model.
- *
*/
public class HeartBeatResponse {
private long responseId;
-
- List<ExecutionCommand> executionCommands = new ArrayList<ExecutionCommand>();
- List<StatusCommand> statusCommands = new ArrayList<StatusCommand>();
- List<CancelCommand> cancelCommands = new ArrayList<CancelCommand>();
- RegistrationCommand registrationCommand;
+ private List<ExecutionCommand> executionCommands = new ArrayList<ExecutionCommand>();
+ private List<StatusCommand> statusCommands = new ArrayList<StatusCommand>();
+ private List<CancelCommand> cancelCommands = new ArrayList<CancelCommand>();
+
+ private RegistrationCommand registrationCommand;
+
+ private boolean restartAgent = false;
+ private boolean hasMappedComponents = false;
- boolean restartAgent = false;
- boolean hasMappedComponents = false;
+ /**
+ * A mapping between cluster name and the alert defintion hash for that
+ * cluster. The alert definition hash for a cluster is a hashed value of all
+ * of the UUIDs for each alert definition that the agent host should be
+ * scheduling. If any of the alert definitions change, their UUID will change
+ * which will cause this hash value to change.
+ */
+ private Map<String, String> alertDefinitionHashes = null;
@JsonProperty("responseId")
public long getResponseId() {
@@ -111,6 +119,16 @@ public class HeartBeatResponse {
this.hasMappedComponents = hasMappedComponents;
}
+ @JsonProperty("alertDefinitionHashes")
+ public Map<String, String> getAlertDefinitionHash() {
+ return alertDefinitionHashes;
+ }
+
+ @JsonProperty("alertDefinitionHashes")
+ public void setAlertDefinitionHash(Map<String, String> alertDefinitionHashes) {
+ this.alertDefinitionHashes = alertDefinitionHashes;
+ }
+
public void addExecutionCommand(ExecutionCommand execCmd) {
executionCommands.add(execCmd);
}
@@ -125,13 +143,15 @@ public class HeartBeatResponse {
@Override
public String toString() {
- return "HeartBeatResponse{" +
- "responseId=" + responseId +
- ", executionCommands=" + executionCommands +
- ", statusCommands=" + statusCommands +
- ", cancelCommands=" + cancelCommands +
- ", registrationCommand=" + registrationCommand +
- ", restartAgent=" + restartAgent +
- '}';
+ StringBuilder buffer = new StringBuilder("HeartBeatResponse{");
+ buffer.append("responseId=").append(responseId);
+ buffer.append(", executionCommands=").append(executionCommands);
+ buffer.append(", statusCommands=").append(statusCommands);
+ buffer.append(", cancelCommands=").append(cancelCommands);
+ buffer.append(", registrationCommand=").append(registrationCommand);
+ buffer.append(", restartAgent=").append(restartAgent);
+ buffer.append(", alertDefinitionHashes=").append(alertDefinitionHashes);
+ buffer.append('}');
+ return buffer.toString();
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/84b988bc/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
index 6f00c27..fd8210b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProvider.java
@@ -64,13 +64,14 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
protected static final String ALERT_DEF_COMPONENT_NAME = "AlertDefinition/component_name";
protected static final String ALERT_DEF_ENABLED = "AlertDefinition/enabled";
protected static final String ALERT_DEF_SCOPE = "AlertDefinition/scope";
-
+ protected static final String ALERT_DEF_UUID = "AlertDefinition/uuid";
+
private static Set<String> pkPropertyIds = new HashSet<String>(
Arrays.asList(ALERT_DEF_ID, ALERT_DEF_NAME));
private static AlertDefinitionDAO alertDefinitionDAO = null;
-
+
private static Gson gson = new Gson();
-
+
/**
* @param instance
*/
@@ -78,13 +79,13 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
public static void init(AlertDefinitionDAO instance) {
alertDefinitionDAO = instance;
}
-
+
AlertDefinitionResourceProvider(Set<String> propertyIds,
Map<Resource.Type, String> keyPropertyIds,
AmbariManagementController managementController) {
super(propertyIds, keyPropertyIds, managementController);
}
-
+
@Override
protected Set<String> getPKPropertyIds() {
return pkPropertyIds;
@@ -103,49 +104,55 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
}
});
notifyCreate(Resource.Type.AlertDefinition, request);
-
+
return getRequestStatus(null);
}
-
+
private void createAlertDefinitions(Set<Map<String, Object>> requestMaps)
throws AmbariException {
List<AlertDefinitionEntity> entities = new ArrayList<AlertDefinitionEntity>();
-
+
for (Map<String, Object> requestMap : requestMaps) {
entities.add(toCreateEntity(requestMap));
}
// !!! TODO multi-create in a transaction
- for (AlertDefinitionEntity entity : entities)
+ for (AlertDefinitionEntity entity : entities) {
alertDefinitionDAO.create(entity);
+ }
}
-
+
private AlertDefinitionEntity toCreateEntity(Map<String, Object> requestMap)
throws AmbariException {
String clusterName = (String) requestMap.get(ALERT_DEF_CLUSTER_NAME);
-
- if (null == clusterName || clusterName.isEmpty())
+
+ if (null == clusterName || clusterName.isEmpty()) {
throw new IllegalArgumentException("Invalid argument, cluster name is required");
-
- if (!requestMap.containsKey(ALERT_DEF_INTERVAL))
+ }
+
+ if (!requestMap.containsKey(ALERT_DEF_INTERVAL)) {
throw new IllegalArgumentException("Check interval must be specified");
-
+ }
+
Integer interval = Integer.valueOf((String) requestMap.get(ALERT_DEF_INTERVAL));
- if (!requestMap.containsKey(ALERT_DEF_NAME))
+ if (!requestMap.containsKey(ALERT_DEF_NAME)) {
throw new IllegalArgumentException("Definition name must be specified");
-
- if (!requestMap.containsKey(ALERT_DEF_SERVICE_NAME))
+ }
+
+ if (!requestMap.containsKey(ALERT_DEF_SERVICE_NAME)) {
throw new IllegalArgumentException("Service name must be specified");
-
- if (!requestMap.containsKey(ALERT_DEF_SOURCE_TYPE))
+ }
+
+ if (!requestMap.containsKey(ALERT_DEF_SOURCE_TYPE)) {
throw new IllegalArgumentException(String.format(
"Source type must be specified and one of %s", EnumSet.allOf(
SourceType.class)));
+ }
JsonObject jsonObj = new JsonObject();
-
+
for (Entry<String, Object> entry : requestMap.entrySet()) {
String propCat = PropertyHelper.getPropertyCategory(entry.getKey());
String propName = PropertyHelper.getPropertyName(entry.getKey());
@@ -155,11 +162,12 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
}
}
- if (0 == jsonObj.entrySet().size())
+ if (0 == jsonObj.entrySet().size()) {
throw new IllegalArgumentException("Source must be specified");
-
+ }
+
Cluster cluster = getManagementController().getClusters().getCluster(clusterName);
-
+
AlertDefinitionEntity entity = new AlertDefinitionEntity();
entity.setClusterId(Long.valueOf(cluster.getClusterId()));
entity.setComponentName((String) requestMap.get(ALERT_DEF_COMPONENT_NAME));
@@ -167,14 +175,14 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
boolean enabled = requestMap.containsKey(ALERT_DEF_ENABLED) ?
Boolean.parseBoolean((String)requestMap.get(ALERT_DEF_ENABLED)) : true;
-
+
entity.setEnabled(enabled);
entity.setHash(UUID.randomUUID().toString());
entity.setScheduleInterval(interval);
entity.setServiceName((String) requestMap.get(ALERT_DEF_SERVICE_NAME));
entity.setSourceType((String) requestMap.get(ALERT_DEF_SOURCE_TYPE));
entity.setSource(jsonObj.toString());
-
+
Scope scope = null;
String desiredScope = (String) requestMap.get(ALERT_DEF_SCOPE);
if (null != desiredScope && desiredScope.length() > 0) {
@@ -190,17 +198,18 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
public Set<Resource> getResources(Request request, Predicate predicate)
throws SystemException, UnsupportedPropertyException,
NoSuchResourceException, NoSuchParentResourceException {
-
+
Set<String> requestPropertyIds = getRequestPropertyIds(request, predicate);
-
+
Set<Resource> results = new HashSet<Resource>();
-
+
for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
String clusterName = (String) propertyMap.get(ALERT_DEF_CLUSTER_NAME);
-
- if (null == clusterName || clusterName.isEmpty())
+
+ if (null == clusterName || clusterName.isEmpty()) {
throw new IllegalArgumentException("Invalid argument, cluster name is required");
-
+ }
+
String id = (String) propertyMap.get(ALERT_DEF_ID);
if (null != id) {
AlertDefinitionEntity entity = alertDefinitionDAO.findById(Long.parseLong(id));
@@ -208,14 +217,14 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
results.add(toResource(false, clusterName, entity, requestPropertyIds));
}
} else {
-
+
Cluster cluster = null;
try {
cluster = getManagementController().getClusters().getCluster(clusterName);
} catch (AmbariException e) {
throw new NoSuchResourceException("Parent Cluster resource doesn't exist", e);
}
-
+
List<AlertDefinitionEntity> entities = alertDefinitionDAO.findAll(
cluster.getClusterId());
@@ -224,7 +233,7 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
}
}
}
-
+
return results;
}
@@ -236,40 +245,44 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
for (Map<String, Object> requestPropMap : request.getProperties()) {
for (Map<String, Object> propertyMap : getPropertyMaps(requestPropMap, predicate)) {
Long id = (Long) propertyMap.get(ALERT_DEF_ID);
-
+
AlertDefinitionEntity entity = alertDefinitionDAO.findById(id.longValue());
- if (null == entity)
+ if (null == entity) {
continue;
+ }
- if (propertyMap.containsKey(ALERT_DEF_NAME))
+ if (propertyMap.containsKey(ALERT_DEF_NAME)) {
entity.setDefinitionName((String) propertyMap.get(ALERT_DEF_NAME));
-
+ }
+
if (propertyMap.containsKey(ALERT_DEF_ENABLED)) {
entity.setEnabled(Boolean.parseBoolean(
(String) propertyMap.get(ALERT_DEF_ENABLED)));
}
-
+
if (propertyMap.containsKey(ALERT_DEF_INTERVAL)) {
entity.setScheduleInterval(Integer.valueOf(
(String) propertyMap.get(ALERT_DEF_INTERVAL)));
}
-
+
if (propertyMap.containsKey(ALERT_DEF_SCOPE)){
Scope scope = null;
String desiredScope = (String) propertyMap.get(ALERT_DEF_SCOPE);
-
- if (null != desiredScope && desiredScope.length() > 0)
+
+ if (null != desiredScope && desiredScope.length() > 0) {
scope = Scope.valueOf((desiredScope));
-
+ }
+
entity.setScope(scope);
}
-
- if (propertyMap.containsKey(ALERT_DEF_SOURCE_TYPE))
+
+ if (propertyMap.containsKey(ALERT_DEF_SOURCE_TYPE)) {
entity.setSourceType((String) propertyMap.get(ALERT_DEF_SOURCE_TYPE));
-
+ }
+
JsonObject jsonObj = new JsonObject();
-
+
for (Entry<String, Object> entry : propertyMap.entrySet()) {
String propCat = PropertyHelper.getPropertyCategory(entry.getKey());
String propName = PropertyHelper.getPropertyName(entry.getKey());
@@ -278,16 +291,16 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
jsonObj.addProperty(propName, entry.getValue().toString());
}
}
-
+
entity.setHash(UUID.randomUUID().toString());
-
+
alertDefinitionDAO.merge(entity);
}
}
-
+
notifyUpdate(Resource.Type.AlertDefinition, request, predicate);
- return getRequestStatus(null);
+ return getRequestStatus(null);
}
@Override
@@ -297,7 +310,7 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
Set<Resource> resources = getResources(
new RequestImpl(null, null, null, null), predicate);
-
+
Set<Long> definitionIds = new HashSet<Long>();
for (final Resource resource : resources) {
@@ -307,7 +320,7 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
for (Long definitionId : definitionIds) {
LOG.info("Deleting alert definition {}", definitionId);
-
+
final AlertDefinitionEntity ad = alertDefinitionDAO.findById(definitionId.longValue());
modifyResources(new Command<Void>() {
@@ -323,11 +336,11 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
return getRequestStatus(null);
}
-
+
private Resource toResource(boolean isCollection, String clusterName,
AlertDefinitionEntity entity, Set<String> requestedIds) {
Resource resource = new ResourceImpl(Resource.Type.AlertDefinition);
-
+
setResourceProperty(resource, ALERT_DEF_CLUSTER_NAME, clusterName, requestedIds);
setResourceProperty(resource, ALERT_DEF_ID, entity.getDefinitionId(), requestedIds);
setResourceProperty(resource, ALERT_DEF_NAME, entity.getDefinitionName(), requestedIds);
@@ -337,22 +350,24 @@ public class AlertDefinitionResourceProvider extends AbstractControllerResourceP
setResourceProperty(resource, ALERT_DEF_ENABLED, Boolean.valueOf(entity.getEnabled()), requestedIds);
setResourceProperty(resource, ALERT_DEF_SCOPE, entity.getScope(), requestedIds);
setResourceProperty(resource, ALERT_DEF_SOURCE_TYPE, entity.getSourceType(), requestedIds);
-
+ setResourceProperty(resource, ALERT_DEF_UUID, entity.getHash(),
+ requestedIds);
+
if (!isCollection && null != resource.getPropertyValue(ALERT_DEF_SOURCE_TYPE)) {
-
+
try {
Map<String, String> map = gson.<Map<String, String>>fromJson(entity.getSource(), Map.class);
-
+
for (Entry<String, String> entry : map.entrySet()) {
String subProp = PropertyHelper.getPropertyId(ALERT_DEF_SOURCE, entry.getKey());
- resource.setProperty(subProp, entry.getValue());
+ resource.setProperty(subProp, entry.getValue());
}
} catch (Exception e) {
LOG.error("Could not coerce alert JSON into a type");
}
}
-
+
return resource;
}
-
+
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/84b988bc/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
index 05881e4..db5c63f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAO.java
@@ -17,12 +17,16 @@
*/
package org.apache.ambari.server.orm.dao;
+import java.util.Collections;
import java.util.List;
+import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
+import org.apache.ambari.server.controller.RootServiceResponseFactory;
import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.state.alert.Scope;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -61,7 +65,7 @@ public class AlertDefinitionDAO {
/**
* Gets an alert definition with the specified ID.
- *
+ *
* @param definitionId
* the ID of the definition to retrieve.
* @return the alert definition or {@code null} if none exists.
@@ -74,7 +78,7 @@ public class AlertDefinitionDAO {
/**
* Gets an alert definition with the specified name. Alert definition names
* are unique within a cluster.
- *
+ *
* @param clusterId
* the ID of the cluster.
* @param definitionName
@@ -93,7 +97,7 @@ public class AlertDefinitionDAO {
/**
* Gets all alert definitions stored in the database.
- *
+ *
* @return all alert definitions or an empty list if none exist (never
* {@code null}).
*/
@@ -106,7 +110,7 @@ public class AlertDefinitionDAO {
/**
* Gets all alert definitions stored in the database.
- *
+ *
* @return all alert definitions or empty list if none exist (never
* {@code null}).
*/
@@ -120,8 +124,114 @@ public class AlertDefinitionDAO {
}
/**
+ * Gets all alert definitions for the given service in the specified cluster.
+ *
+ * @param clusterId
+ * the ID of the cluster.
+ * @param serviceName
+ * the name of the service.
+ *
+ * @return all alert definitions for the service or empty list if none exist
+ * (never {@code null}).
+ */
+ public List<AlertDefinitionEntity> findByService(long clusterId,
+ String serviceName) {
+ TypedQuery<AlertDefinitionEntity> query = entityManagerProvider.get().createNamedQuery(
+ "AlertDefinitionEntity.findByService", AlertDefinitionEntity.class);
+
+ query.setParameter("clusterId", clusterId);
+ query.setParameter("serviceName", serviceName);
+
+ return daoUtils.selectList(query);
+ }
+
+ /**
+ * Gets all alert definitions for the specified services that do not have a
+ * component. These definitions are assumed to be run on the master hosts.
+ *
+ * @param clusterId
+ * the ID of the cluster.
+ * @param services
+ * the services to match on.
+ *
+ * @return all alert definitions for the services or empty list if none exist
+ * (never {@code null}).
+ */
+ public List<AlertDefinitionEntity> findByServiceMaster(long clusterId,
+ Set<String> services) {
+ if (null == services || services.size() == 0) {
+ return Collections.emptyList();
+ }
+
+ TypedQuery<AlertDefinitionEntity> query = entityManagerProvider.get().createNamedQuery(
+ "AlertDefinitionEntity.findByServiceMaster",
+ AlertDefinitionEntity.class);
+
+ query.setParameter("clusterId", clusterId);
+ query.setParameter("services", services);
+ query.setParameter("scope", Scope.SERVICE);
+
+ return daoUtils.selectList(query);
+ }
+
+ /**
+ * Gets all alert definitions that are not bound to a particular service. An
+ * example of this type of definition is a host capacity alert.
+ *
+ * @param clusterId
+ * the ID of the cluster.
+ * @param serviceName
+ * the name of the service (not {@code null}).
+ * @param componentName
+ * the name of the service component (not {@code null}).
+ * @return all alert definitions that are not bound to a service or an empty
+ * list (never {@code null}).
+ */
+ public List<AlertDefinitionEntity> findByServiceComponent(long clusterId,
+ String serviceName, String componentName) {
+ if (null == serviceName || null == componentName) {
+ return Collections.emptyList();
+ }
+
+ TypedQuery<AlertDefinitionEntity> query = entityManagerProvider.get().createNamedQuery(
+ "AlertDefinitionEntity.findByServiceAndComponent",
+ AlertDefinitionEntity.class);
+
+ query.setParameter("clusterId", clusterId);
+ query.setParameter("serviceName", serviceName);
+ query.setParameter("componentName", componentName);
+
+ return daoUtils.selectList(query);
+ }
+
+ /**
+ * Gets all alert definitions that are not bound to a particular service. An
+ * example of this type of definition is a host capacity alert.
+ *
+ * @param clusterId
+ * the ID of the cluster.
+ * @return all alert definitions that are not bound to a service or an empty
+ * list (never {@code null}).
+ */
+ public List<AlertDefinitionEntity> findAgentScoped(long clusterId) {
+ TypedQuery<AlertDefinitionEntity> query = entityManagerProvider.get().createNamedQuery(
+ "AlertDefinitionEntity.findByServiceAndComponent",
+ AlertDefinitionEntity.class);
+
+ query.setParameter("clusterId", clusterId);
+
+ query.setParameter("serviceName",
+ RootServiceResponseFactory.Services.AMBARI.name());
+
+ query.setParameter("componentName",
+ RootServiceResponseFactory.Components.AMBARI_AGENT.name());
+
+ return daoUtils.selectList(query);
+ }
+
+ /**
* Persists a new alert definition.
- *
+ *
* @param alertDefinition
* the definition to persist (not {@code null}).
*/
@@ -132,7 +242,7 @@ public class AlertDefinitionDAO {
/**
* Refresh the state of the alert definition from the database.
- *
+ *
* @param alertDefinition
* the definition to refresh (not {@code null}).
*/
@@ -144,7 +254,7 @@ public class AlertDefinitionDAO {
/**
* Merge the speicified alert definition with the existing definition in the
* database.
- *
+ *
* @param alertDefinition
* the definition to merge (not {@code null}).
* @return the updated definition with merged content (never {@code null}).
@@ -157,7 +267,7 @@ public class AlertDefinitionDAO {
/**
* Removes the specified alert definition and all related history and
* associations from the database.
- *
+ *
* @param alertDefinition
* the definition to remove.
*/
@@ -170,7 +280,8 @@ public class AlertDefinitionDAO {
EntityManager entityManager = entityManagerProvider.get();
alertDefinition = findById(alertDefinition.getDefinitionId());
- if (null != alertDefinition)
+ if (null != alertDefinition) {
entityManager.remove(alertDefinition);
+ }
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/84b988bc/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
index de30921..66a3af0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/AlertDefinitionEntity.java
@@ -50,9 +50,12 @@ import org.apache.ambari.server.state.alert.Scope;
"cluster_id", "definition_name" }))
@TableGenerator(name = "alert_definition_id_generator", table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "value", pkColumnValue = "alert_definition_id_seq", initialValue = 0, allocationSize = 1)
@NamedQueries({
- @NamedQuery(name = "AlertDefinitionEntity.findAll", query = "SELECT alertDefinition FROM AlertDefinitionEntity alertDefinition"),
- @NamedQuery(name = "AlertDefinitionEntity.findAllInCluster", query = "SELECT alertDefinition FROM AlertDefinitionEntity alertDefinition WHERE alertDefinition.clusterId = :clusterId"),
- @NamedQuery(name = "AlertDefinitionEntity.findByName", query = "SELECT alertDefinition FROM AlertDefinitionEntity alertDefinition WHERE alertDefinition.definitionName = :definitionName AND alertDefinition.clusterId = :clusterId"), })
+ @NamedQuery(name = "AlertDefinitionEntity.findAll", query = "SELECT ad FROM AlertDefinitionEntity ad"),
+ @NamedQuery(name = "AlertDefinitionEntity.findAllInCluster", query = "SELECT ad FROM AlertDefinitionEntity ad WHERE ad.clusterId = :clusterId"),
+ @NamedQuery(name = "AlertDefinitionEntity.findByName", query = "SELECT ad FROM AlertDefinitionEntity ad WHERE ad.definitionName = :definitionName AND ad.clusterId = :clusterId"),
+ @NamedQuery(name = "AlertDefinitionEntity.findByService", query = "SELECT ad FROM AlertDefinitionEntity ad WHERE ad.serviceName = :serviceName AND ad.clusterId = :clusterId"),
+ @NamedQuery(name = "AlertDefinitionEntity.findByServiceAndComponent", query = "SELECT ad FROM AlertDefinitionEntity ad WHERE ad.serviceName = :serviceName AND ad.componentName = :componentName AND ad.clusterId = :clusterId"),
+ @NamedQuery(name = "AlertDefinitionEntity.findByServiceMaster", query = "SELECT ad FROM AlertDefinitionEntity ad WHERE ad.serviceName IN :services AND ad.scope = :scope AND ad.clusterId = :clusterId") })
public class AlertDefinitionEntity {
@Id
http://git-wip-us.apache.org/repos/asf/ambari/blob/84b988bc/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
new file mode 100644
index 0000000..1f31c35
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertDefinitionHash.java
@@ -0,0 +1,272 @@
+/**
+ * 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.ambari.server.state.alert;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceComponent;
+import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.commons.codec.binary.Hex;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * The {@link AlertDefinitionHash} class is used to generate an MD5 hash for a
+ * list of {@link AlertDefinitionEntity}s. It is used in order to represent the
+ * state of a group of definitions by using
+ * {@link AlertDefinitionEntity#getHash()}
+ */
+@Singleton
+public class AlertDefinitionHash {
+
+ /**
+ * Logger.
+ */
+ private final static Logger LOG = LoggerFactory.getLogger(AlertDefinitionHash.class);
+
+ /**
+ * The hash returned when there are no definitions to hash.
+ */
+ public static String NULL_MD5_HASH = "37a6259cc0c1dae299a7866489dff0bd";
+
+ /**
+ * DAO for retrieving {@link AlertDefinitionEntity} instances.
+ */
+ @Inject
+ private AlertDefinitionDAO m_definitionDao;
+
+ /**
+ * All clusters.
+ */
+ @Inject
+ private Clusters m_clusters;
+
+ /**
+ * The hashes for all hosts.
+ */
+ private Map<String, String> m_hashes = new ConcurrentHashMap<String, String>();
+
+ /**
+ * Gets a unique hash value reprssenting all of the alert definitions that
+ * should be scheduled to run on a given host.
+ * <p/>
+ * This will not include alert definitions where the type is defined as
+ * {@link SourceType#AGGREGATE} since aggregate definitions are not scheduled
+ * to run on agent hosts.
+ * <p/>
+ * Hash values from this method are cached.
+ *
+ * @param clusterName
+ * the cluster name (not {@code null}).
+ * @param hostName
+ * the host name (not {@code null}).
+ * @return the unique hash or {@value #NULL_MD5_HASH} if none.
+ */
+ public String getHash(String clusterName, String hostName) {
+ String hash = m_hashes.get(hostName);
+ if (null != hash) {
+ return hash;
+ }
+
+ hash = hash(clusterName, hostName);
+ m_hashes.put(hostName, hash);
+
+ return hash;
+ }
+
+ /**
+ * Gets a mapping between cluster and alert definition hashes for all of the
+ * clusters that the given host belongs to.
+ *
+ * @param hostName
+ * the host name (not {@code null}).
+ * @return a mapping between cluster and alert definition hash or an empty map
+ * (never @code null).
+ * @see #getHash(String, String)
+ * @throws AmbariException
+ */
+ public Map<String, String> getHashes(String hostName)
+ throws AmbariException {
+ Set<Cluster> clusters = m_clusters.getClustersForHost(hostName);
+ if (null == clusters || clusters.size() == 0) {
+ return Collections.emptyMap();
+ }
+
+ Map<String, String> hashes = new HashMap<String, String>();
+ for (Cluster cluster : clusters) {
+ String clusterName = cluster.getClusterName();
+ String hash = getHash(clusterName, hostName);
+ hashes.put(clusterName, hash);
+ }
+
+ return hashes;
+ }
+
+ /**
+ * Gets the alert definitions for the specified host. This will include the
+ * following types of alert definitions:
+ * <ul>
+ * <li>Service/Component alerts</li>
+ * <li>Service alerts where the host is a MASTER</li>
+ * <li>Host alerts that are not bound to a service</li>
+ * </ul>
+ *
+ * @param clusterName
+ * the cluster name (not {@code null}).
+ * @param hostName
+ * the host name (not {@code null}).
+ * @return the alert definitions for the host, or an empty set (never
+ * {@code null}).
+ */
+ public Set<AlertDefinitionEntity> getAlertDefinitions(String clusterName,
+ String hostName) {
+ Set<AlertDefinitionEntity> definitions = new HashSet<AlertDefinitionEntity>();
+
+ try {
+ Cluster cluster = m_clusters.getCluster(clusterName);
+ if (null == cluster) {
+ LOG.warn("Unable to get alert definitions for the missing cluster {}",
+ clusterName);
+
+ return Collections.emptySet();
+ }
+
+ long clusterId = cluster.getClusterId();
+ List<ServiceComponentHost> serviceComponents = cluster.getServiceComponentHosts(hostName);
+ if (null == serviceComponents || serviceComponents.size() == 0) {
+ LOG.warn(
+ "Unable to get alert definitions for {} since there are no service components defined",
+ hostName);
+
+ return Collections.emptySet();
+ }
+
+ for (ServiceComponentHost serviceComponent : serviceComponents) {
+ String serviceName = serviceComponent.getServiceName();
+ String componentName = serviceComponent.getServiceComponentName();
+
+ // add all alerts for this service/component pair
+ definitions.addAll(m_definitionDao.findByServiceComponent(
+ clusterId, serviceName, componentName));
+ }
+
+ // for every service, get the master components and see if the host
+ // is a master
+ Set<String> services = new HashSet<String>();
+ for (Entry<String, Service> entry : cluster.getServices().entrySet()) {
+ Service service = entry.getValue();
+ Map<String, ServiceComponent> components = service.getServiceComponents();
+ for (Entry<String, ServiceComponent> component : components.entrySet()) {
+ if (component.getValue().isMasterComponent()) {
+ Map<String, ServiceComponentHost> hosts = component.getValue().getServiceComponentHosts();
+
+ if( hosts.containsKey( hostName ) ){
+ services.add(service.getName());
+ }
+ }
+ }
+ }
+
+ // add all service scoped alerts
+ if( services.size() > 0 ){
+ definitions.addAll(m_definitionDao.findByServiceMaster(clusterId,
+ services));
+ }
+
+ // add any alerts not bound to a service (host level alerts)
+ definitions.addAll(m_definitionDao.findAgentScoped(clusterId));
+ } catch (AmbariException ambariException) {
+ LOG.error("Unable to get alert definitions", ambariException);
+ return Collections.emptySet();
+ }
+
+ return definitions;
+ }
+
+ /**
+ * Calculates a unique hash value representing all of the alert definitions
+ * that should be scheduled to run on a given host. Alerts of type
+ * {@link SourceType#AGGREGATE} are not included in the hash since they are
+ * not run on the agents.
+ *
+ * @param clusterName
+ * the cluster name (not {@code null}).
+ * @param hostName
+ * the host name (not {@code null}).
+ * @return the unique hash or {@value #NULL_MD5_HASH} if none.
+ */
+ private String hash(String clusterName, String hostName) {
+ Set<AlertDefinitionEntity> definitions = getAlertDefinitions(clusterName,
+ hostName);
+
+ // no definitions found for this host, don't bother hashing
+ if( null == definitions || definitions.size() == 0 ) {
+ return NULL_MD5_HASH;
+ }
+
+ // strip out all AGGREGATE types
+ Iterator<AlertDefinitionEntity> iterator = definitions.iterator();
+ while (iterator.hasNext()) {
+ if (SourceType.AGGREGATE.equals(iterator.next().getSourceType())) {
+ iterator.remove();
+ }
+ }
+
+ // build the UUIDs
+ List<String> uuids = new ArrayList<String>(definitions.size());
+ for (AlertDefinitionEntity definition : definitions) {
+ uuids.add(definition.getHash());
+ }
+
+ // sort the UUIDs so that the digest is created with bytes in the same order
+ Collections.sort(uuids);
+
+ try {
+ MessageDigest digest = MessageDigest.getInstance("MD5");
+ for (String uuid : uuids) {
+ digest.update(uuid.getBytes());
+ }
+
+ byte[] hashBytes = digest.digest();
+ return Hex.encodeHexString(hashBytes);
+ } catch (NoSuchAlgorithmException nsae) {
+ LOG.warn("Unable to calculate MD5 alert definition hash", nsae);
+ return NULL_MD5_HASH;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/84b988bc/ambari-server/src/main/resources/properties.json
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/properties.json b/ambari-server/src/main/resources/properties.json
index e515b91..e80c0e6 100644
--- a/ambari-server/src/main/resources/properties.json
+++ b/ambari-server/src/main/resources/properties.json
@@ -420,7 +420,8 @@
"AlertDefinition/interval",
"AlertDefinition/enabled",
"AlertDefinition/scope",
- "AlertDefinition/source"
+ "AlertDefinition/source",
+ "AlertDefinition/uuid"
],
"Controller":[
"Controllers/name",
http://git-wip-us.apache.org/repos/asf/ambari/blob/84b988bc/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java
index fc57389..c6e26e8 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AlertDefinitionResourceProviderTest.java
@@ -34,6 +34,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.spi.Predicate;
@@ -56,59 +57,65 @@ import org.junit.Test;
public class AlertDefinitionResourceProviderTest {
AlertDefinitionDAO dao = null;
-
+
+ private static String DEFINITION_UUID = UUID.randomUUID().toString();
+
@Before
public void before() {
dao = createStrictMock(AlertDefinitionDAO.class);
-
+
AlertDefinitionResourceProvider.init(dao);
}
-
+
@Test
public void testGetResourcesNoPredicate() throws Exception {
AlertDefinitionResourceProvider provider = createProvider(null);
-
+
Request request = PropertyHelper.getReadRequest("AlertDefinition/cluster_name",
"AlertDefinition/id");
-
+
Set<Resource> results = provider.getResources(request, null);
-
+
assertEquals(0, results.size());
- }
+ }
@Test
public void testGetResourcesClusterPredicate() throws Exception {
Request request = PropertyHelper.getReadRequest(
AlertDefinitionResourceProvider.ALERT_DEF_CLUSTER_NAME,
AlertDefinitionResourceProvider.ALERT_DEF_ID,
- AlertDefinitionResourceProvider.ALERT_DEF_NAME);
-
+ AlertDefinitionResourceProvider.ALERT_DEF_NAME,
+ AlertDefinitionResourceProvider.ALERT_DEF_UUID);
+
AmbariManagementController amc = createMock(AmbariManagementController.class);
Clusters clusters = createMock(Clusters.class);
Cluster cluster = createMock(Cluster.class);
expect(amc.getClusters()).andReturn(clusters).atLeastOnce();
expect(clusters.getCluster((String) anyObject())).andReturn(cluster).atLeastOnce();
expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes();
-
+
Predicate predicate = new PredicateBuilder().property(
- AlertDefinitionResourceProvider.ALERT_DEF_CLUSTER_NAME).equals("c1").toPredicate();
-
+ AlertDefinitionResourceProvider.ALERT_DEF_CLUSTER_NAME).equals("c1").toPredicate();
+
expect(dao.findAll(1L)).andReturn(getMockEntities());
replay(amc, clusters, cluster, dao);
-
- AlertDefinitionResourceProvider provider = createProvider(amc);
+
+ AlertDefinitionResourceProvider provider = createProvider(amc);
Set<Resource> results = provider.getResources(request, predicate);
-
+
assertEquals(1, results.size());
-
+
Resource r = results.iterator().next();
-
+
Assert.assertEquals("my_def", r.getPropertyValue(AlertDefinitionResourceProvider.ALERT_DEF_NAME));
-
+
+ Assert.assertEquals(DEFINITION_UUID,
+ r.getPropertyValue(AlertDefinitionResourceProvider.ALERT_DEF_UUID));
+
verify(amc, clusters, cluster, dao);
}
-
+
@Test
public void testGetSingleResource() throws Exception {
Request request = PropertyHelper.getReadRequest(
@@ -116,29 +123,29 @@ public class AlertDefinitionResourceProviderTest {
AlertDefinitionResourceProvider.ALERT_DEF_ID,
AlertDefinitionResourceProvider.ALERT_DEF_NAME,
AlertDefinitionResourceProvider.ALERT_DEF_SOURCE_TYPE);
-
+
AmbariManagementController amc = createMock(AmbariManagementController.class);
Clusters clusters = createMock(Clusters.class);
Cluster cluster = createMock(Cluster.class);
expect(amc.getClusters()).andReturn(clusters).atLeastOnce();
expect(clusters.getCluster((String) anyObject())).andReturn(cluster).atLeastOnce();
expect(cluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes();
-
+
Predicate predicate = new PredicateBuilder().property(
AlertDefinitionResourceProvider.ALERT_DEF_CLUSTER_NAME).equals("c1")
- .and().property(AlertDefinitionResourceProvider.ALERT_DEF_ID).equals("1").toPredicate();
-
+ .and().property(AlertDefinitionResourceProvider.ALERT_DEF_ID).equals("1").toPredicate();
+
expect(dao.findById(1L)).andReturn(getMockEntities().get(0));
replay(amc, clusters, cluster, dao);
-
- AlertDefinitionResourceProvider provider = createProvider(amc);
+
+ AlertDefinitionResourceProvider provider = createProvider(amc);
Set<Resource> results = provider.getResources(request, predicate);
-
+
assertEquals(1, results.size());
-
+
Resource r = results.iterator().next();
-
+
Assert.assertEquals("my_def", r.getPropertyValue(AlertDefinitionResourceProvider.ALERT_DEF_NAME));
Assert.assertEquals("metric", r.getPropertyValue(AlertDefinitionResourceProvider.ALERT_DEF_SOURCE_TYPE));
Assert.assertNotNull(r.getPropertyValue("AlertDefinition/source/type"));
@@ -156,24 +163,24 @@ public class AlertDefinitionResourceProviderTest {
Capture<AlertDefinitionEntity> entityCapture = new Capture<AlertDefinitionEntity>();
dao.create(capture(entityCapture));
expectLastCall();
-
+
replay(amc, clusters, cluster, dao);
-
+
AlertDefinitionResourceProvider provider = createProvider(amc);
-
+
Map<String, Object> requestProps = new HashMap<String, Object>();
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_CLUSTER_NAME, "c1");
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_INTERVAL, "1");
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_NAME, "my_def");
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_SERVICE_NAME, "HDFS");
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_SOURCE_TYPE, "METRIC");
-
+
Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null);
provider.createResources(request);
-
+
Assert.assertTrue(entityCapture.hasCaptured());
- AlertDefinitionEntity entity = entityCapture.getValue();
+ AlertDefinitionEntity entity = entityCapture.getValue();
Assert.assertNotNull(entity);
Assert.assertEquals(Long.valueOf(1), entity.getClusterId());
@@ -186,11 +193,11 @@ public class AlertDefinitionResourceProviderTest {
Assert.assertEquals("HDFS", entity.getServiceName());
Assert.assertNotNull(entity.getSource());
Assert.assertEquals("METRIC", entity.getSourceType());
-
+
verify(amc, clusters, cluster, dao);
}
-
+
@Test
public void testUpdateResources() throws Exception {
AmbariManagementController amc = createMock(AmbariManagementController.class);
@@ -203,40 +210,40 @@ public class AlertDefinitionResourceProviderTest {
Capture<AlertDefinitionEntity> entityCapture = new Capture<AlertDefinitionEntity>();
dao.create(capture(entityCapture));
expectLastCall();
-
+
replay(amc, clusters, cluster, dao);
-
+
Map<String, Object> requestProps = new HashMap<String, Object>();
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_CLUSTER_NAME, "c1");
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_INTERVAL, "1");
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_NAME, "my_def");
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_SERVICE_NAME, "HDFS");
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_SOURCE_TYPE, "METRIC");
-
+
Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null);
AlertDefinitionResourceProvider provider = createProvider(amc);
-
+
provider.createResources(request);
-
+
Assert.assertTrue(entityCapture.hasCaptured());
- AlertDefinitionEntity entity = entityCapture.getValue();
+ AlertDefinitionEntity entity = entityCapture.getValue();
Assert.assertNotNull(entity);
-
+
Predicate p = new PredicateBuilder().property(
AlertDefinitionResourceProvider.ALERT_DEF_ID).equals("1").and().property(
AlertDefinitionResourceProvider.ALERT_DEF_CLUSTER_NAME).equals("c1").toPredicate();
// everything is mocked, there is no DB
entity.setDefinitionId(Long.valueOf(1));
-
+
String oldName = entity.getDefinitionName();
String oldHash = entity.getHash();
-
+
resetToStrict(dao);
expect(dao.findById(1L)).andReturn(entity).anyTimes();
expect(dao.merge((AlertDefinitionEntity) anyObject())).andReturn(entity).anyTimes();
replay(dao);
-
+
requestProps = new HashMap<String, Object>();
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_CLUSTER_NAME, "c1");
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_INTERVAL, "1");
@@ -244,15 +251,15 @@ public class AlertDefinitionResourceProviderTest {
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_SERVICE_NAME, "HDFS");
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_SOURCE_TYPE, "METRIC");
request = PropertyHelper.getUpdateRequest(requestProps, null);
-
+
provider.updateResources(request, p);
Assert.assertFalse(oldHash.equals(entity.getHash()));
Assert.assertFalse(oldName.equals(entity.getDefinitionName()));
-
+
verify(amc, clusters, cluster, dao);
}
-
+
@Test
public void testDeleteResources() throws Exception {
AmbariManagementController amc = createMock(AmbariManagementController.class);
@@ -265,9 +272,9 @@ public class AlertDefinitionResourceProviderTest {
Capture<AlertDefinitionEntity> entityCapture = new Capture<AlertDefinitionEntity>();
dao.create(capture(entityCapture));
expectLastCall();
-
+
replay(amc, clusters, cluster, dao);
-
+
AlertDefinitionResourceProvider provider = createProvider(amc);
Map<String, Object> requestProps = new HashMap<String, Object>();
@@ -276,43 +283,43 @@ public class AlertDefinitionResourceProviderTest {
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_NAME, "my_def");
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_SERVICE_NAME, "HDFS");
requestProps.put(AlertDefinitionResourceProvider.ALERT_DEF_SOURCE_TYPE, "METRIC");
-
+
Request request = PropertyHelper.getCreateRequest(Collections.singleton(requestProps), null);
provider.createResources(request);
Assert.assertTrue(entityCapture.hasCaptured());
- AlertDefinitionEntity entity = entityCapture.getValue();
+ AlertDefinitionEntity entity = entityCapture.getValue();
Assert.assertNotNull(entity);
-
+
Predicate p = new PredicateBuilder().property(
AlertDefinitionResourceProvider.ALERT_DEF_ID).equals("1").and().property(
AlertDefinitionResourceProvider.ALERT_DEF_CLUSTER_NAME).equals("c1").toPredicate();
// everything is mocked, there is no DB
entity.setDefinitionId(Long.valueOf(1));
-
+
resetToStrict(dao);
expect(dao.findById(1L)).andReturn(entity).anyTimes();
dao.remove(capture(entityCapture));
expectLastCall();
replay(dao);
-
+
provider.deleteResources(p);
-
+
AlertDefinitionEntity entity1 = entityCapture.getValue();
Assert.assertEquals(Long.valueOf(1), entity1.getDefinitionId());
-
+
verify(amc, clusters, cluster, dao);
-
+
}
-
+
private AlertDefinitionResourceProvider createProvider(AmbariManagementController amc) {
return new AlertDefinitionResourceProvider(
PropertyHelper.getPropertyIds(Resource.Type.AlertDefinition),
PropertyHelper.getKeyPropertyIds(Resource.Type.AlertDefinition),
amc);
}
-
+
private List<AlertDefinitionEntity> getMockEntities() {
AlertDefinitionEntity entity = new AlertDefinitionEntity();
entity.setClusterId(Long.valueOf(1L));
@@ -320,13 +327,12 @@ public class AlertDefinitionResourceProviderTest {
entity.setDefinitionId(Long.valueOf(1L));
entity.setDefinitionName("my_def");
entity.setEnabled(true);
- entity.setHash("tmphash");
+ entity.setHash(DEFINITION_UUID);
entity.setScheduleInterval(Integer.valueOf(2));
entity.setServiceName(null);
entity.setSourceType("metric");
entity.setSource("{'jmx': 'beanName/attributeName', 'host': '{{aa:123445}}'}");
-
+
return Arrays.asList(entity);
}
-
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/84b988bc/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
index f2ddcd7..d621a9b 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AlertDefinitionDAOTest.java
@@ -28,6 +28,7 @@ import java.util.List;
import java.util.TimeZone;
import java.util.UUID;
+import org.apache.ambari.server.controller.RootServiceResponseFactory;
import org.apache.ambari.server.orm.GuiceJpaInitializer;
import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
import org.apache.ambari.server.orm.OrmTestHelper;
@@ -41,7 +42,6 @@ import org.apache.ambari.server.state.MaintenanceState;
import org.apache.ambari.server.state.NotificationState;
import org.apache.ambari.server.state.alert.Scope;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -65,7 +65,7 @@ public class AlertDefinitionDAOTest {
OrmTestHelper helper;
/**
- *
+ *
*/
@Before
public void setup() {
@@ -78,7 +78,9 @@ public class AlertDefinitionDAOTest {
helper = injector.getInstance(OrmTestHelper.class);
clusterId = helper.createCluster();
- for (int i = 0; i < 8; i++) {
+ // create 8 HDFS alerts
+ int i = 0;
+ for (; i < 8; i++) {
AlertDefinitionEntity definition = new AlertDefinitionEntity();
definition.setDefinitionName("Alert Definition " + i);
definition.setServiceName("HDFS");
@@ -91,6 +93,58 @@ public class AlertDefinitionDAOTest {
definition.setSourceType("SCRIPT");
dao.create(definition);
}
+
+ // create 2 HDFS with components
+ for (; i < 10; i++) {
+ AlertDefinitionEntity definition = new AlertDefinitionEntity();
+ definition.setDefinitionName("Alert Definition " + i);
+ definition.setServiceName("HDFS");
+
+ if (i == 9) {
+ definition.setComponentName("NAMENODE");
+ } else {
+ definition.setComponentName("DATANODE");
+ }
+
+ definition.setClusterId(clusterId);
+ definition.setHash(UUID.randomUUID().toString());
+ definition.setScheduleInterval(60);
+ definition.setScope(Scope.SERVICE);
+ definition.setSource("Source " + i);
+ definition.setSourceType("SCRIPT");
+ dao.create(definition);
+ }
+
+ // create 2 host scoped
+ for (; i < 12; i++) {
+ AlertDefinitionEntity definition = new AlertDefinitionEntity();
+ definition.setDefinitionName("Alert Definition " + i);
+ definition.setServiceName("OOZIE");
+ definition.setComponentName("OOZIE_SERVER");
+ definition.setClusterId(clusterId);
+ definition.setHash(UUID.randomUUID().toString());
+ definition.setScheduleInterval(60);
+ definition.setScope(Scope.HOST);
+ definition.setSource("Source " + i);
+ definition.setSourceType("SCRIPT");
+ dao.create(definition);
+ }
+
+ // create 3 agent alerts
+ for (; i < 15; i++) {
+ AlertDefinitionEntity definition = new AlertDefinitionEntity();
+ definition.setDefinitionName("Alert Definition " + i);
+ definition.setServiceName(RootServiceResponseFactory.Services.AMBARI.name());
+ definition.setComponentName(RootServiceResponseFactory.Components.AMBARI_AGENT.name());
+ definition.setClusterId(clusterId);
+ definition.setHash(UUID.randomUUID().toString());
+ definition.setScheduleInterval(60);
+ definition.setScope(Scope.HOST);
+ definition.setSource("Source " + i);
+ definition.setSourceType("SCRIPT");
+ dao.create(definition);
+ }
+
}
@After
@@ -100,40 +154,77 @@ public class AlertDefinitionDAOTest {
}
/**
- *
+ *
*/
@Test
public void testFindByName() {
List<AlertDefinitionEntity> definitions = dao.findAll();
- Assert.assertNotNull(definitions);
+ assertNotNull(definitions);
AlertDefinitionEntity definition = definitions.get(2);
AlertDefinitionEntity retrieved = dao.findByName(
definition.getClusterId(), definition.getDefinitionName());
- Assert.assertEquals(definition, retrieved);
+ assertEquals(definition, retrieved);
}
/**
- *
+ *
*/
@Test
public void testFindAll() {
List<AlertDefinitionEntity> definitions = dao.findAll();
- Assert.assertNotNull(definitions);
- Assert.assertEquals(8, definitions.size());
+ assertNotNull(definitions);
+ assertEquals(15, definitions.size());
}
/**
- *
+ *
*/
@Test
- public void findById() {
+ public void testFindById() {
List<AlertDefinitionEntity> definitions = dao.findAll();
- Assert.assertNotNull(definitions);
+ assertNotNull(definitions);
AlertDefinitionEntity definition = definitions.get(2);
AlertDefinitionEntity retrieved = dao.findById(definition.getDefinitionId());
+ assertEquals(definition, retrieved);
+ }
+
+ /**
+ *
+ */
+ @Test
+ public void testFindByService() {
+ List<AlertDefinitionEntity> definitions = dao.findByService(clusterId,
+ "HDFS");
+
+ assertNotNull(definitions);
+ assertEquals(10, definitions.size());
+
+ definitions = dao.findByService(clusterId, "YARN");
+ assertNotNull(definitions);
+ assertEquals(0, definitions.size());
+ }
- Assert.assertEquals(definition, retrieved);
+ /**
+ *
+ */
+ @Test
+ public void testFindByServiceComponent() {
+ List<AlertDefinitionEntity> definitions = dao.findByServiceComponent(
+ clusterId, "OOZIE", "OOZIE_SERVER");
+
+ assertNotNull(definitions);
+ assertEquals(2, definitions.size());
+ }
+
+ /**
+ *
+ */
+ @Test
+ public void testFindAgentScoped() {
+ List<AlertDefinitionEntity> definitions = dao.findAgentScoped(clusterId);
+ assertNotNull(definitions);
+ assertEquals(3, definitions.size());
}
@Test
http://git-wip-us.apache.org/repos/asf/ambari/blob/84b988bc/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertDefinitionHashTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertDefinitionHashTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertDefinitionHashTest.java
new file mode 100644
index 0000000..937417a
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/alerts/AlertDefinitionHashTest.java
@@ -0,0 +1,224 @@
+/**
+ * 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.ambari.server.state.alerts;
+
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.expect;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import junit.framework.TestCase;
+
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
+import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceComponent;
+import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.alert.AlertDefinitionHash;
+import org.apache.ambari.server.state.alert.Scope;
+import org.easymock.EasyMock;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.inject.Binder;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import com.google.inject.util.Modules;
+
+/**
+ * Tests for {@link AlertDefinitionHash}.
+ */
+public class AlertDefinitionHashTest extends TestCase {
+
+ private AlertDefinitionHash m_hash;
+ private Clusters m_mockClusters;
+ private Cluster m_mockCluster;
+ private AlertDefinitionDAO m_mockDao;
+ private Injector m_injector;
+
+ private static final String CLUSTERNAME = "cluster1";
+ private static final String HOSTNAME = "c6401.ambari.apache.org";
+
+ /**
+ *
+ */
+ @Override
+ @Before
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ m_injector = Guice.createInjector(Modules.override(
+ new InMemoryDefaultTestModule()).with(new MockModule()));
+
+ m_mockClusters = m_injector.getInstance(Clusters.class);
+ m_mockCluster = m_injector.getInstance(Cluster.class);
+ m_mockDao = m_injector.getInstance(AlertDefinitionDAO.class);
+
+ // add HDFS/NN
+ List<ServiceComponentHost> serviceComponentHosts = new ArrayList<ServiceComponentHost>();
+ ServiceComponentHost sch = EasyMock.createNiceMock(ServiceComponentHost.class);
+ expect(sch.getServiceName()).andReturn("HDFS").anyTimes();
+ expect(sch.getServiceComponentName()).andReturn("NAMENODE").anyTimes();
+ expect(sch.getHostName()).andReturn(HOSTNAME).anyTimes();
+ EasyMock.replay(sch);
+ serviceComponentHosts.add(sch);
+
+ // add HDFS/DN
+ sch = EasyMock.createNiceMock(ServiceComponentHost.class);
+ expect(sch.getServiceName()).andReturn("HDFS").anyTimes();
+ expect(sch.getServiceComponentName()).andReturn("DATANODE").anyTimes();
+ expect(sch.getHostName()).andReturn(HOSTNAME).anyTimes();
+ EasyMock.replay(sch);
+ serviceComponentHosts.add(sch);
+
+ Map<String, ServiceComponentHost> mapComponentHosts = new HashMap<String, ServiceComponentHost>();
+ ServiceComponentHost host = EasyMock.createNiceMock(ServiceComponentHost.class);
+ expect(host.getHostName()).andReturn(HOSTNAME).anyTimes();
+ mapComponentHosts.put(HOSTNAME, host);
+
+ Map<String, ServiceComponent> serviceComponents = new HashMap<String, ServiceComponent>();
+ ServiceComponent namenode = EasyMock.createNiceMock(ServiceComponent.class);
+ expect(namenode.getServiceComponentHosts()).andReturn(mapComponentHosts).anyTimes();
+ expect(namenode.isMasterComponent()).andReturn(true).anyTimes();
+ serviceComponents.put("NAMENODE", namenode);
+
+ // create HDFS for the cluster
+ Map<String, Service> services = new HashMap<String, Service>();
+ String hdfsName = "HDFS";
+ Service hdfs = EasyMock.createNiceMock(Service.class);
+ expect(hdfs.getName()).andReturn("HDFS").anyTimes();
+ expect(hdfs.getServiceComponents()).andReturn(serviceComponents).anyTimes();
+ services.put(hdfsName, hdfs);
+
+ // replay
+ EasyMock.replay(hdfs, host, namenode);
+
+ // Clusters mock
+ expect(m_mockClusters.getCluster((String) anyObject())).andReturn(
+ m_mockCluster).atLeastOnce();
+
+ // cluster mock
+ expect(m_mockCluster.getClusterId()).andReturn(Long.valueOf(1)).anyTimes();
+ expect(m_mockCluster.getClusterName()).andReturn(CLUSTERNAME).anyTimes();
+ expect(m_mockCluster.getServices()).andReturn(services).anyTimes();
+ expect(
+ m_mockCluster.getServiceComponentHosts(EasyMock.anyObject(String.class))).andReturn(
+ serviceComponentHosts).anyTimes();
+
+ AlertDefinitionEntity hdfsService = new AlertDefinitionEntity();
+ hdfsService.setDefinitionId(1L);
+ hdfsService.setClusterId(1L);
+ hdfsService.setHash(UUID.randomUUID().toString());
+ hdfsService.setServiceName("HDFS");
+ hdfsService.setComponentName("NAMENODE");
+ hdfsService.setScope(Scope.SERVICE);
+
+ AlertDefinitionEntity hdfsHost = new AlertDefinitionEntity();
+ hdfsHost.setDefinitionId(2L);
+ hdfsHost.setClusterId(1L);
+ hdfsHost.setHash(UUID.randomUUID().toString());
+ hdfsHost.setServiceName("HDFS");
+ hdfsHost.setComponentName("DATANODE");
+ hdfsHost.setScope(Scope.HOST);
+
+ AlertDefinitionEntity agentScoped = new AlertDefinitionEntity();
+ agentScoped.setDefinitionId(3L);
+ agentScoped.setClusterId(1L);
+ agentScoped.setHash(UUID.randomUUID().toString());
+ agentScoped.setServiceName("AMBARI");
+ agentScoped.setComponentName("AMBARI_AGENT");
+ agentScoped.setScope(Scope.HOST);
+
+ EasyMock.expect(
+ m_mockDao.findByServiceMaster(EasyMock.anyInt(),
+ (Set<String>) EasyMock.anyObject())).andReturn(
+ Collections.singletonList(hdfsService)).anyTimes();
+
+ EasyMock.expect(
+ m_mockDao.findByServiceComponent(EasyMock.anyInt(),
+ EasyMock.anyObject(String.class), EasyMock.anyObject(String.class))).andReturn(
+ Collections.singletonList(hdfsHost)).anyTimes();
+
+ EasyMock.expect(m_mockDao.findAgentScoped(EasyMock.anyInt())).andReturn(
+ Collections.singletonList(agentScoped)).anyTimes();
+
+ EasyMock.replay(m_mockClusters, m_mockCluster, m_mockDao);
+ m_hash = m_injector.getInstance(AlertDefinitionHash.class);
+ }
+
+ /**
+ *
+ */
+ @Override
+ @After
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Test method for {@link org.apache.ambari.server.state.alert.AlertDefinitionHash#getHash(java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testGetHash() {
+ String hash = m_hash.getHash(CLUSTERNAME, HOSTNAME);
+ assertNotNull(hash);
+ assertNotSame(AlertDefinitionHash.NULL_MD5_HASH, hash);
+ assertEquals(hash, m_hash.getHash(CLUSTERNAME, HOSTNAME));
+ }
+
+ /**
+ * Test method for {@link org.apache.ambari.server.state.alert.AlertDefinitionHash#getAlertDefinitions(java.lang.String, java.lang.String)}.
+ */
+ @Test
+ public void testGetAlertDefinitions() {
+ Set<AlertDefinitionEntity> definitions = m_hash.getAlertDefinitions(
+ CLUSTERNAME, HOSTNAME);
+
+ assertEquals(3, definitions.size());
+ }
+
+ /**
+ *
+ */
+ private class MockModule implements Module {
+ /**
+ *
+ */
+ @Override
+ public void configure(Binder binder) {
+ binder.bind(Clusters.class).toInstance(
+ EasyMock.createNiceMock(Clusters.class));
+ binder.bind(Cluster.class).toInstance(
+ EasyMock.createNiceMock(Cluster.class));
+ binder.bind(AlertDefinitionDAO.class).toInstance(
+ EasyMock.createNiceMock(AlertDefinitionDAO.class));
+ }
+ }
+}
[4/6] git commit: AMBARI-6852. Views: views list from API is not
respecting privileges.
Posted by jo...@apache.org.
AMBARI-6852. Views: views list from API is not respecting privileges.
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/f3bd5cc8
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/f3bd5cc8
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/f3bd5cc8
Branch: refs/heads/branch-alerts-dev
Commit: f3bd5cc8cec545b3513c8442d42957b5fea71cd3
Parents: 2a617da
Author: Siddharth Wagle <sw...@hortonworks.com>
Authored: Wed Aug 13 12:42:32 2014 -0700
Committer: Siddharth Wagle <sw...@hortonworks.com>
Committed: Wed Aug 13 12:43:32 2014 -0700
----------------------------------------------------------------------
.../internal/ViewResourceProvider.java | 41 ++++++++++++++++----
1 file changed, 33 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/f3bd5cc8/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewResourceProvider.java
index b76c8e0..6a83793 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewResourceProvider.java
@@ -28,6 +28,7 @@ import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
import org.apache.ambari.server.controller.spi.SystemException;
import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
import org.apache.ambari.server.orm.entities.ViewEntity;
+import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
import org.apache.ambari.server.view.ViewRegistry;
import java.util.Collections;
@@ -63,7 +64,7 @@ public class ViewResourceProvider extends AbstractResourceProvider {
propertyIds.add(VIEW_NAME_PROPERTY_ID);
}
-
+
// ----- Constructors ------------------------------------------------------
/**
@@ -73,12 +74,12 @@ public class ViewResourceProvider extends AbstractResourceProvider {
super(propertyIds, keyPropertyIds);
}
-
+
// ----- ResourceProvider --------------------------------------------------
@Override
- public RequestStatus createResources(Request request)
- throws SystemException, UnsupportedPropertyException,
+ public RequestStatus createResources(Request request)
+ throws SystemException, UnsupportedPropertyException,
ResourceAlreadyExistsException, NoSuchParentResourceException {
throw new UnsupportedOperationException("Not yet supported.");
}
@@ -102,11 +103,13 @@ public class ViewResourceProvider extends AbstractResourceProvider {
for (ViewEntity viewDefinition : viewRegistry.getDefinitions()){
if (viewName == null || viewName.equals(viewDefinition.getCommonName())) {
- Resource resource = new ResourceImpl(Resource.Type.View);
+ if (includeDefinition(viewDefinition, true)) {
+ Resource resource = new ResourceImpl(Resource.Type.View);
- setResourceProperty(resource, VIEW_NAME_PROPERTY_ID, viewDefinition.getCommonName(), requestedIds);
+ setResourceProperty(resource, VIEW_NAME_PROPERTY_ID, viewDefinition.getCommonName(), requestedIds);
- resources.add(resource);
+ resources.add(resource);
+ }
}
}
}
@@ -130,7 +133,29 @@ public class ViewResourceProvider extends AbstractResourceProvider {
return keyPropertyIds;
}
-
+ /**
+ * Determine whether or not the given view definition resource should be included
+ * based on the permissions granted to the current user.
+ *
+ * @param definitionEntity the view definition entity
+ * @param readOnly indicate whether or not this is for a read only operation
+ *
+ * @return true if the view instance should be included based on the permissions of the current user
+ */
+ private boolean includeDefinition(ViewEntity definitionEntity, boolean readOnly) {
+
+ ViewRegistry viewRegistry = ViewRegistry.getInstance();
+
+ boolean allowed = false;
+
+ for (ViewInstanceEntity instanceEntity: definitionEntity.getInstances()) {
+ allowed |= viewRegistry.checkPermission(instanceEntity, readOnly);
+ }
+
+ return allowed;
+ }
+
+
// ----- AbstractResourceProvider ------------------------------------------
@Override
[2/6] git commit: AMBARI-6849 Admin: remove "roles" prop from users.
(Buzhor Denys via ababiichuk)
Posted by jo...@apache.org.
AMBARI-6849 Admin: remove "roles" prop from users. (Buzhor Denys via ababiichuk)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/efc6eee8
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/efc6eee8
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/efc6eee8
Branch: refs/heads/branch-alerts-dev
Commit: efc6eee8d9f272ad389924584abb8f21073ecd15
Parents: 1eaf6a9
Author: aBabiichuk <ab...@cybervisiontech.com>
Authored: Wed Aug 13 19:01:59 2014 +0300
Committer: aBabiichuk <ab...@cybervisiontech.com>
Committed: Wed Aug 13 19:02:17 2014 +0300
----------------------------------------------------------------------
.../app/assets/data/users/privileges.json | 14 ++++
.../app/assets/data/users/privileges_admin.json | 14 ++++
.../controllers/global/cluster_controller.js | 48 +++++++++--
ambari-web/app/mappers/users_mapper.js | 20 +++--
ambari-web/app/models/user.js | 17 ++--
ambari-web/app/router.js | 87 ++++++++++++--------
ambari-web/app/utils/ajax/ajax.js | 12 +++
ambari-web/app/views/main/admin/user/create.js | 15 +---
ambari-web/app/views/main/admin/user/edit.js | 15 +---
ambari-web/test/mappers/users_mapper_test.js | 7 +-
.../test/views/main/admin/user/create_test.js | 25 ------
.../test/views/main/admin/user/edit_test.js | 25 ------
12 files changed, 167 insertions(+), 132 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/efc6eee8/ambari-web/app/assets/data/users/privileges.json
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/data/users/privileges.json b/ambari-web/app/assets/data/users/privileges.json
new file mode 100644
index 0000000..a461206
--- /dev/null
+++ b/ambari-web/app/assets/data/users/privileges.json
@@ -0,0 +1,14 @@
+{
+ "href" : "http://c6401.ambari.apache.org:8080/api/v1/privileges?PrivilegeInfo/principal_name=admin&fields=PrivilegeInfo/*",
+ "items" : [
+ {
+ "href" : "http://c6401.ambari.apache.org:8080/api/v1/privileges/1",
+ "PrivilegeInfo" : {
+ "permission_name" : "AMBARI.ADMIN",
+ "principal_name" : "admin",
+ "principal_type" : "USER",
+ "privilege_id" : 1
+ }
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/efc6eee8/ambari-web/app/assets/data/users/privileges_admin.json
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/data/users/privileges_admin.json b/ambari-web/app/assets/data/users/privileges_admin.json
new file mode 100644
index 0000000..a461206
--- /dev/null
+++ b/ambari-web/app/assets/data/users/privileges_admin.json
@@ -0,0 +1,14 @@
+{
+ "href" : "http://c6401.ambari.apache.org:8080/api/v1/privileges?PrivilegeInfo/principal_name=admin&fields=PrivilegeInfo/*",
+ "items" : [
+ {
+ "href" : "http://c6401.ambari.apache.org:8080/api/v1/privileges/1",
+ "PrivilegeInfo" : {
+ "permission_name" : "AMBARI.ADMIN",
+ "principal_name" : "admin",
+ "principal_type" : "USER",
+ "privilege_id" : 1
+ }
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/efc6eee8/ambari-web/app/controllers/global/cluster_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/cluster_controller.js b/ambari-web/app/controllers/global/cluster_controller.js
index 77bcccd..ba1006c 100644
--- a/ambari-web/app/controllers/global/cluster_controller.js
+++ b/ambari-web/app/controllers/global/cluster_controller.js
@@ -259,7 +259,6 @@ App.ClusterController = Em.Controller.extend({
return;
}
var clusterUrl = this.getUrl('/data/clusters/cluster.json', '?fields=Clusters');
- var usersUrl = App.get('testMode') ? '/data/users/users.json' : App.get('apiPrefix') + '/users/?fields=*';
var racksUrl = "/data/racks/racks.json";
@@ -292,13 +291,7 @@ App.ClusterController = Em.Controller.extend({
});
}
- App.HttpClient.get(usersUrl, App.usersMapper, {
- complete: function (jqXHR, textStatus) {
- self.updateLoadStatus('users');
- }
- }, function (jqXHR, textStatus) {
- self.updateLoadStatus('users');
- });
+ this.loadUsersInfo();
/**
* Order of loading:
@@ -433,6 +426,45 @@ App.ClusterController = Em.Controller.extend({
console.warn('can\'t get ambari properties');
},
+ /**
+ * Load info about users.
+ **/
+ loadUsersInfo: function() {
+ return App.ajax.send({
+ name: 'users.all',
+ sender: this,
+ success: 'loadUsersSuccess',
+ error: 'loadUsersError'
+ });
+ },
+
+ loadUsersSuccess: function(data) {
+ App.ajax.send({
+ name: 'users.privileges',
+ sender: this,
+ data: {
+ users: data
+ },
+ success: 'loadUsersPrivilegesSuccess'
+ });
+ },
+
+ loadUsersError: function() {
+ this.updateLoadStatus('users');
+ },
+ /**
+ * Load privileges, check relations between user and privilege,
+ * map users using <code>App.usersMappper</code>.
+ **/
+ loadUsersPrivilegesSuccess: function(data, opt, params) {
+ params.users.items.forEach(function(user) {
+ user.privileges = {};
+ user.privileges.items = data.items.filterProperty('PrivilegeInfo.principal_name', user.Users.user_name);
+ });
+ App.usersMapper.map(params.users);
+ this.updateLoadStatus('users');
+ },
+
updateClusterData: function () {
var testUrl = App.get('isHadoop2Stack') ? '/data/clusters/HDP2/cluster.json' : '/data/clusters/cluster.json';
var clusterUrl = this.getUrl(testUrl, '?fields=Clusters');
http://git-wip-us.apache.org/repos/asf/ambari/blob/efc6eee8/ambari-web/app/mappers/users_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/users_mapper.js b/ambari-web/app/mappers/users_mapper.js
index f85f682..19b3098 100644
--- a/ambari-web/app/mappers/users_mapper.js
+++ b/ambari-web/app/mappers/users_mapper.js
@@ -23,22 +23,32 @@ App.usersMapper = App.QuickDataMapper.create({
config : {
id : 'Users.user_name',
user_name : 'Users.user_name',
- roles : 'Users.roles',
is_ldap: 'Users.ldap_user',
- admin: 'Users.admin'
+ admin: 'Users.admin',
+ permissions: 'permissions'
},
map: function (json) {
var self = this;
json.items.forEach(function (item) {
var result= [];
if(!App.User.find().someProperty("userName", item.Users.user_name)) {
- item.Users.admin = self.isAdmin(item.Users.roles);
+ item.permissions = [];
+ if (!!Em.get(item.privileges, 'items.length')) {
+ item.permissions = item.privileges.items.mapProperty('PrivilegeInfo.permission_name');
+ }
+ item.Users.admin = self.isAdmin(item.permissions);
result.push(self.parseIt(item, self.config));
App.store.loadMany(self.get('model'), result);
}
});
},
- isAdmin: function(roles) {
- return (roles.indexOf("admin") >= 0);
+
+ /**
+ * Check if user is admin.
+ * @param {Array} permissionList
+ * @return {Boolean}
+ **/
+ isAdmin: function(permissionList) {
+ return permissionList.indexOf('AMBARI.ADMIN') > -1 || permissionList.indexOf('CLUSTER.OPERATOR') > -1;
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/efc6eee8/ambari-web/app/models/user.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/user.js b/ambari-web/app/models/user.js
index d1f1b9a..d8729e2 100644
--- a/ambari-web/app/models/user.js
+++ b/ambari-web/app/models/user.js
@@ -24,7 +24,6 @@ App.User = DS.Model.extend({
id:function(){
return this.get('userName');
}.property('userName'),
- roles:DS.attr('string'),
isLdap:DS.attr('boolean'),
type: function(){
if(this.get('isLdap')){
@@ -33,7 +32,17 @@ App.User = DS.Model.extend({
return 'Local';
}.property('isLdap'),
auditItems:DS.hasMany('App.ServiceAudit'),
- admin: DS.attr('boolean')
+ admin: DS.attr('boolean'),
+ /**
+ * List of permissions assigned to user
+ * Available permissions:
+ * AMBARI.ADMIN
+ * CLUSTER.READ
+ * CLUSTER.OPERATE
+ * VIEW.USE
+ * @property {Array} permissions
+ **/
+ permissions: DS.attr('array')
});
App.EditUserForm = App.Form.extend({
@@ -48,7 +57,6 @@ App.EditUserForm = App.Form.extend({
{ name:"new_password", displayName:"New Password", displayType:"password", isRequired: false },
{ name:"new_passwordRetype", displayName:"Retype New Password", displayType:"password", isRequired: false },
{ name:"admin", displayName:"Admin", displayType:"checkbox", isRequired:false },
- { name:"roles", displayName:"Role", isRequired:false, isHidden:true },
{ name:"isLdap", displayName:"Type", isRequired:false, isHidden:true }
],
fields:[],
@@ -116,8 +124,7 @@ App.CreateUserForm = App.Form.extend({
{ name:"userName", displayName:"Username", toLowerCase: function(){var v = this.get('value'); this.set('value', v.toLowerCase())}.observes('value') },
{ name:"password", displayName:"Password", displayType:"password", isRequired: true },
{ name:"passwordRetype", displayName:"Retype Password", displayType:"password", validator:"passwordRetype", isRequired: true },
- { name:"admin", displayName:"Admin", displayType:"checkbox", isRequired:false, defaultValue: true},
- { name:"roles", displayName:"Role", isRequired:false, isHidden:true }
+ { name:"admin", displayName:"Admin", displayType:"checkbox", isRequired:false, defaultValue: true}
],
fields:[],
http://git-wip-us.apache.org/repos/asf/ambari/blob/efc6eee8/ambari-web/app/router.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/router.js b/ambari-web/app/router.js
index 505b760..8bc0cf3 100644
--- a/ambari-web/app/router.js
+++ b/ambari-web/app/router.js
@@ -155,6 +155,37 @@ App.Router = Em.Router.extend({
return App.db.getUser();
},
+ /**
+ * Get user privileges.
+ *
+ * @param {String} userName
+ * @returns {$.Deferred}
+ **/
+ getUserPrivileges: function(userName) {
+ return App.ajax.send({
+ name: 'router.user.privileges',
+ sender: this,
+ data: {
+ userName: userName
+ },
+ success: 'getUserPrivilegesSuccess'
+ });
+ },
+
+ getUserPrivilegesSuccess: function() {},
+
+ setUserLoggedIn: function(userName) {
+ var controller = this.get('loginController'),
+ self = this;
+ this.setAuthenticated(true);
+ this.setLoginName(userName);
+ this.setUser(App.User.find().findProperty('id', userName));
+ this.getSection(function(route){
+ self.transitionTo(route);
+ controller.postLogin(true,true);
+ });
+ },
+
login: function () {
var controller = this.get('loginController');
var loginName = controller.get('loginName').toLowerCase();
@@ -191,33 +222,30 @@ App.Router = Em.Router.extend({
loginSuccessCallback: function(data, opt, params) {
console.log('login success');
- var d = data;
- var isAdmin = data.Users.roles.indexOf('admin') >= 0;
+ var isAdmin = false;
var self = this;
- if (isAdmin) {
- App.set('isAdmin', true);
- var controller = this.get('loginController');
- this.setAuthenticated(true);
- this.setLoginName(params.loginName);
+ this.getUserPrivileges(data.Users.user_name).done(function(privileges) {
+ data.privileges = privileges;
App.usersMapper.map({"items": [data]});
- this.setUser(App.User.find().findProperty('id', params.loginName));
- this.getSection(function(route){
- self.transitionTo(route);
- controller.postLogin(true,true);
- });
- }
- else {
- App.ajax.send({
- name: 'router.login2',
- sender: this,
- data: {
- loginName: params.loginName,
- loginData: data
- },
- success: 'login2SuccessCallback',
- error: 'login2ErrorCallback'
- });
- }
+ isAdmin = App.usersMapper.isAdmin(privileges.items.mapProperty('PrivilegeInfo.permission_name'));
+ if (isAdmin) {
+ App.set('isAdmin', true);
+ self.setUserLoggedIn(params.loginName);
+ return true;
+ }
+ else {
+ return App.ajax.send({
+ name: 'router.login2',
+ sender: self,
+ data: {
+ loginName: params.loginName,
+ loginData: data
+ },
+ success: 'login2SuccessCallback',
+ error: 'login2ErrorCallback'
+ });
+ }
+ });
},
loginErrorCallback: function(request, ajaxOptions, error, opt) {
@@ -234,16 +262,9 @@ App.Router = Em.Router.extend({
login2SuccessCallback: function (clusterResp, opt, params) {
var controller = this.get('loginController');
- var self = this;
if (clusterResp.items.length) {
- this.setAuthenticated(true);
- this.setLoginName(params.loginName);
App.usersMapper.map({"items": [params.loginData]});
- this.setUser(App.User.find().findProperty('id', params.loginName));
- this.getSection(function(route){
- self.transitionTo(route);
- controller.postLogin(true,true);
- });
+ this.setUserLoggedIn(params.loginName);
}
else {
controller.set('errorMessage', Em.I18n.t('router.hadoopClusterNotSetUp'));
http://git-wip-us.apache.org/repos/asf/ambari/blob/efc6eee8/ambari-web/app/utils/ajax/ajax.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js
index 0de25d4..64a3fcc 100644
--- a/ambari-web/app/utils/ajax/ajax.js
+++ b/ambari-web/app/utils/ajax/ajax.js
@@ -1332,6 +1332,18 @@ var urls = {
};
}
},
+ 'users.all': {
+ real: '/users/?fields=*',
+ mock: '/data/users/users.json'
+ },
+ 'users.privileges': {
+ real: '/privileges?fields=*',
+ mock: '/data/users/privileges.json'
+ },
+ 'router.user.privileges': {
+ real: '/privileges?PrivilegeInfo/principal_name={userName}&fields=*',
+ mock: '/data/users/privileges_{userName}.json'
+ },
'router.login2': {
'real': '/clusters',
'mock': '/data/clusters/info.json'
http://git-wip-us.apache.org/repos/asf/ambari/blob/efc6eee8/ambari-web/app/views/main/admin/user/create.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/admin/user/create.js b/ambari-web/app/views/main/admin/user/create.js
index d6f33d9..12d5607 100644
--- a/ambari-web/app/views/main/admin/user/create.js
+++ b/ambari-web/app/views/main/admin/user/create.js
@@ -46,8 +46,6 @@ App.MainAdminUserCreateView = Em.View.extend({
var form = this.get("userForm");
if (!form.isValid()) return false;
- this.identifyRoles(form);
-
return !!App.ajax.send({
name: 'admin.user.create',
sender: this,
@@ -56,8 +54,7 @@ App.MainAdminUserCreateView = Em.View.extend({
form: form,
data: {
Users: {
- password: form.getField("password").get('value'),
- roles: form.getField("roles").get('value')
+ password: form.getField("password").get('value')
}
}
},
@@ -67,16 +64,6 @@ App.MainAdminUserCreateView = Em.View.extend({
},
/**
- * identify roles of user by admin checkbox
- * @param form
- */
- identifyRoles: function (form) {
- var roles = (form.getField("admin").get('value') === true) ? 'admin,user' : 'user';
- form.getField("roles").set("value", roles);
- return roles;
- },
-
- /**
* Success-callback for create user request
* @param {object} data
* @param {object} opts
http://git-wip-us.apache.org/repos/asf/ambari/blob/efc6eee8/ambari-web/app/views/main/admin/user/edit.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/admin/user/edit.js b/ambari-web/app/views/main/admin/user/edit.js
index 64211ea..738de30 100644
--- a/ambari-web/app/views/main/admin/user/edit.js
+++ b/ambari-web/app/views/main/admin/user/edit.js
@@ -42,9 +42,7 @@ App.MainAdminUserEditView = Em.View.extend({
var form = this.get("userForm");
if (!form.isValid()) return false;
- var Users = {
- roles: this.identifyRoles(form)
- };
+ var Users = {};
this.setPassword(Users, form);
@@ -79,17 +77,6 @@ App.MainAdminUserEditView = Em.View.extend({
},
/**
- * identify roles of user by admin checkbox
- * @param form
- * @return {String}
- */
- identifyRoles: function (form) {
- var roles = (form.getField("admin").get('value') === true) ? 'admin,user' : 'user';
- form.getField("roles").set("value", roles);
- return roles;
- },
-
- /**
* Success callback for edit user request
* @param {object} data
* @param {object} opt
http://git-wip-us.apache.org/repos/asf/ambari/blob/efc6eee8/ambari-web/test/mappers/users_mapper_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/mappers/users_mapper_test.js b/ambari-web/test/mappers/users_mapper_test.js
index 6db6f48..20c6bae 100644
--- a/ambari-web/test/mappers/users_mapper_test.js
+++ b/ambari-web/test/mappers/users_mapper_test.js
@@ -26,9 +26,10 @@ describe('App.usersMapper', function () {
describe('#isAdmin', function() {
var tests = [
- {i:'user,admin',e:true,m:'has admin role'},
- {i:'admin,user',e:true,m:'has admin role'},
- {i:'user',e:false,m:'doesn\'t have admin role'}
+ {i:["AMBARI.ADMIN"],e:true,m:'has admin role'},
+ {i:["CLUSTER.READ", "AMBARI.ADMIN"],e:true,m:'has admin role'},
+ {i:["VIEW.USE"],e:false,m:'doesn\'t have admin role'},
+ {i:["CLUSTER.OPERATOR"],e:true,m:'has admin role'}
];
tests.forEach(function(test) {
it(test.m, function() {
http://git-wip-us.apache.org/repos/asf/ambari/blob/efc6eee8/ambari-web/test/views/main/admin/user/create_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/admin/user/create_test.js b/ambari-web/test/views/main/admin/user/create_test.js
index 672e25b..bd5b88c 100644
--- a/ambari-web/test/views/main/admin/user/create_test.js
+++ b/ambari-web/test/views/main/admin/user/create_test.js
@@ -44,40 +44,15 @@ describe('App.MainAdminUserCreateView', function () {
});
it('form is valid', function () {
view.set('userForm.mockIsValid', true);
- sinon.stub(view, 'identifyRoles', Em.K);
sinon.stub(App.ajax, 'send', Em.K);
expect(view.create()).to.be.true;
- expect(view.identifyRoles.calledOnce).to.be.true;
expect(App.ajax.send.calledOnce).to.be.true;
- view.identifyRoles.restore();
App.ajax.send.restore();
});
});
- describe('#identifyRoles()', function () {
- var mock = Em.Object.create();
- var form = Em.Object.create({
- getField: function () {
- return mock;
- }
- });
-
- it('admin is false', function () {
- mock.set('value', false);
-
- expect(view.identifyRoles(form)).to.equal('user');
- expect(mock.get('value')).to.equal('user');
- });
- it('admin is true', function () {
- mock.set('value', true);
-
- expect(view.identifyRoles(form)).to.equal('admin,user');
- expect(mock.get('value')).to.equal('admin,user');
- });
- });
-
describe('#createUserSuccessCallback()', function () {
it('', function () {
http://git-wip-us.apache.org/repos/asf/ambari/blob/efc6eee8/ambari-web/test/views/main/admin/user/edit_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/admin/user/edit_test.js b/ambari-web/test/views/main/admin/user/edit_test.js
index c82fbc1..21cdb2b 100644
--- a/ambari-web/test/views/main/admin/user/edit_test.js
+++ b/ambari-web/test/views/main/admin/user/edit_test.js
@@ -55,16 +55,13 @@ describe('App.MainAdminUserEditView', function () {
sinon.stub(view.get('userForm'), 'isValid', function () {
return true;
});
- sinon.stub(view, 'identifyRoles', Em.K);
sinon.stub(view, 'setPassword', Em.K);
expect(view.edit()).to.be.true;
expect(App.ajax.send.calledOnce).to.be.true;
- expect(view.identifyRoles.calledOnce).to.be.true;
expect(view.setPassword.calledOnce).to.be.true;
- view.identifyRoles.restore();
view.setPassword.restore();
});
});
@@ -109,28 +106,6 @@ describe('App.MainAdminUserEditView', function () {
});
});
- describe('#identifyRoles()', function () {
- var mock = Em.Object.create();
- var form = Em.Object.create({
- getField: function () {
- return mock;
- }
- });
-
- it('admin is false', function () {
- mock.set('value', false);
-
- expect(view.identifyRoles(form)).to.equal('user');
- expect(mock.get('value')).to.equal('user');
- });
- it('admin is true', function () {
- mock.set('value', true);
-
- expect(view.identifyRoles(form)).to.equal('admin,user');
- expect(mock.get('value')).to.equal('admin,user');
- });
- });
-
describe('#editUserSuccessCallback()', function () {
it('', function () {
var params = {
[3/6] git commit: AMBARI-6841. Config History: implement UI
tweaks.(xiwang)
Posted by jo...@apache.org.
AMBARI-6841. Config History: implement UI tweaks.(xiwang)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/2a617da8
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/2a617da8
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/2a617da8
Branch: refs/heads/branch-alerts-dev
Commit: 2a617da83e2483f3733b57cf2600df34784888a6
Parents: efc6eee
Author: Xi Wang <xi...@apache.org>
Authored: Tue Aug 12 18:51:36 2014 -0700
Committer: Xi Wang <xi...@apache.org>
Committed: Wed Aug 13 11:19:11 2014 -0700
----------------------------------------------------------------------
.../main/dashboard/config_history_controller.js | 1 +
ambari-web/app/messages.js | 6 +-
ambari-web/app/models/service_config_version.js | 6 +-
ambari-web/app/styles/application.less | 126 +++++++++----------
.../common/configs/compare_property.hbs | 6 +-
.../common/configs/config_history_flow.hbs | 48 +++----
.../templates/main/dashboard/config_history.hbs | 15 ++-
.../views/common/configs/config_history_flow.js | 4 +-
.../views/main/dashboard/config_history_view.js | 1 -
9 files changed, 108 insertions(+), 105 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/2a617da8/ambari-web/app/controllers/main/dashboard/config_history_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/dashboard/config_history_controller.js b/ambari-web/app/controllers/main/dashboard/config_history_controller.js
index 936634a..aeb3fbc 100644
--- a/ambari-web/app/controllers/main/dashboard/config_history_controller.js
+++ b/ambari-web/app/controllers/main/dashboard/config_history_controller.js
@@ -16,6 +16,7 @@
* limitations under the License.
*/
+var App = require('app');
var customDatePopup = require('/views/common/custom_date_popup');
App.MainConfigHistoryController = Em.ArrayController.extend(App.TableServerMixin, {
http://git-wip-us.apache.org/repos/asf/ambari/blob/2a617da8/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index eb2d0d2..75ef3fc 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -1974,16 +1974,18 @@ Em.I18n.translations = {
'dashboard.services.zookeeper.server' : 'ZooKeeper Server',
'dashboard.configHistory.title': 'Configs',
- 'dashboard.configHistory.table.version.title' : 'Service: version',
+ 'dashboard.configHistory.table.version.title' : 'Service',
'dashboard.configHistory.table.modified.title' : 'Modified',
'dashboard.configHistory.table.empty' : 'No history to display',
+ 'dashboard.configHistory.table.version.versionText' : 'V{0}',
'dashboard.configHistory.table.filteredHostsInfo': '{0} of {1} versions showing',
'dashboard.configHistory.info-bar.authoredOn': 'authored on',
'dashboard.configHistory.info-bar.changesToHandle': 'Changes to handle',
'dashboard.configHistory.info-bar.showMore': 'Show more',
'dashboard.configHistory.info-bar.save.popup.title': 'Save Configuration',
'dashboard.configHistory.info-bar.save.popup.placeholder': 'What did you change?',
- 'dashboard.configHistory.info-bar.revert.button': 'Revert to this version',
+ 'dashboard.configHistory.info-bar.revert.button': 'Make current',
+
'timeRange.presets.1hour':'1h',
'timeRange.presets.12hour':'12h',
http://git-wip-us.apache.org/repos/asf/ambari/blob/2a617da8/ambari-web/app/models/service_config_version.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/service_config_version.js b/ambari-web/app/models/service_config_version.js
index f11859c..4ff3057 100644
--- a/ambari-web/app/models/service_config_version.js
+++ b/ambari-web/app/models/service_config_version.js
@@ -35,9 +35,9 @@ App.ServiceConfigVersion = DS.Model.extend({
var length = this.get('isCurrent') ? 20 : 40;
return (typeof this.get('notes') === 'string') ? this.get('notes').slice(0, length) : "";
}.property('notes', 'isCurrent'),
- serviceVersion: function () {
- return this.get('serviceName') + ': ' + this.get('version');
- }.property('serviceName', 'version'),
+ versionText: function () {
+ return Em.I18n.t('dashboard.configHistory.table.version.versionText').format(this.get('version'));
+ }.property('version'),
modifiedDate: function () {
return dateUtil.dateFormat(this.get('appliedTime'));
}.property('createTime'),
http://git-wip-us.apache.org/repos/asf/ambari/blob/2a617da8/ambari-web/app/styles/application.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less
index bab0daa..5479c1d 100644
--- a/ambari-web/app/styles/application.less
+++ b/ambari-web/app/styles/application.less
@@ -4913,67 +4913,41 @@ ul.inline li {
}
#config_history_flow {
- margin-bottom: 100px;
+ margin-bottom: 80px;
.version-slider {
width: 100%;
height: 100px;
margin: 10px 0;
.flow-element {
- width: 20%;
+ width: 18%;
height: 100%;
.box {
position: relative;
- width: 73%;
- height: 100%;
- background-color: #f1f1f1;
- border: 1px solid #000000;
- font-size: 0.9em;
- .top-right-label {
- font-size: @default-font-size;
- background-color: white;
- position: absolute;
- top: 0;
- left: 0;
+ width: 72%;
+ height: 90%;
+ background-color: #ffffff;
+ border: 1px solid #dddddd;
+ font-size: @default-font-size;
+ .top-label {
min-width: 20px;
- border: solid #000000;
- border-width: 0 1px 1px 0;
padding: 5px;
- text-align: center;
- }
- .date {
- margin-left: 35px;
- line-height: 30px;
- white-space: nowrap;
}
.content {
padding: 0 5px;
- line-height: 16px;
- }
- .current-label {
- position: absolute;
- border-top: 1px solid black;
- bottom: 0;
- left: 0;
- width: 100%;
text-align: center;
- font-weight: bold;
- border-radius: 0;
- padding: 0;
- font-size: 14px;
- line-height: 20px;
+ color: #555555;
}
}
.displayed {
- background-color: #dcdcdc;
+ background-color: #eeeeee;
+ border: 1px solid #dddddd;
}
.arrow-box {
- width: 25%;
- height: 100%;
+ width: 20%;
margin-left: 1px;
- .big-arrow-right {
- height: 100%;
- background-size: 100% 25%;
- background-position: 50% center;
+ margin-top: 20px;
+ .icon-arrow-right {
+ color: #c3c3c3;
}
}
}
@@ -4984,45 +4958,50 @@ ul.inline li {
.box {
width: 100%;
}
- width: 15%;
+ width: 13%;
}
- .arrow-right {
- margin: 20px -15px 20px 10px;
- border-top: 30px solid transparent;
- border-bottom: 30px solid transparent;
- }
- .arrow-left {
- margin: 20px 10px 20px -15px;
- border-top: 30px solid transparent;
- border-bottom: 30px solid transparent;
- }
- .visibleArrow {
- border-right-color: black;
- border-left-color: black;
+ .icon-chevron-box {
+ margin-top: 25px;
+ width: 5%;
+ .icon-chevron-right,
+ .icon-chevron-left{
+ color: #c3c3c3;
+ }
+ .icon-chevron-left:hover,
+ .icon-chevron-right:hover{
+ color: #808080;
+ }
}
}
.version-info-bar {
- height: 60px;
- border: 2px solid #a9a9a9;
- background-color: #dcdcdc;
+ background-image: -moz-linear-gradient(top, @top-nav-bg-color-from, @top-nav-bg-color-to);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@top-nav-bg-color-from), to(@top-nav-bg-color-to));
+ background-image: -webkit-linear-gradient(top, @top-nav-bg-color-from, @top-nav-bg-color-to);
+ background-image: -o-linear-gradient(top, @top-nav-bg-color-from, @top-nav-bg-color-to);
+ background-image: linear-gradient(to bottom, @top-nav-bg-color-from, @top-nav-bg-color-to);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr= @top-nav-bg-color-from, endColorstr=@top-nav-bg-color-to); //for IE9-
+ -webkit-box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
+ -moz-box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
+ box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
margin: 5px 0;
padding: 5px;
position: fixed;
- width: 52%;
z-index: 2;
- min-width: 743px;
+ width: 747px;
.label-wrapper {
line-height: 30px;
margin-left: 10px;
+ color: #d3d3d3;
.label {
font-size: 14px;
padding: 5px;
}
}
.dropdown-menu {
- min-width: 660px;
+ min-width: 400px;
+ margin-top: 4px;
li {
line-height: 30px;
}
@@ -6038,11 +6017,26 @@ i.icon-asterisks {
}
}
}
-
-
-
-
-
+ #config_history_flow {
+ .version-slider {
+ .flow-element {
+ .box {
+ width: 75%;
+ }
+ .arrow-box {
+ margin-left: 5px;
+ }
+ }
+ .first {
+ .box {
+ width: 100%;
+ }
+ }
+ }
+ .version-info-bar {
+ width: 960px;
+ }
+ }
.summary-metric-graphs {
[class*="span"] {
float: left;
http://git-wip-us.apache.org/repos/asf/ambari/blob/2a617da8/ambari-web/app/templates/common/configs/compare_property.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/configs/compare_property.hbs b/ambari-web/app/templates/common/configs/compare_property.hbs
index 6e1a691..f2b2a45 100644
--- a/ambari-web/app/templates/common/configs/compare_property.hbs
+++ b/ambari-web/app/templates/common/configs/compare_property.hbs
@@ -19,10 +19,6 @@
<div {{bindAttr class=":control-group :overrideField"}}>
{{view view.serviceConfigProperty.compareConfig.viewClass serviceConfigBinding="view.serviceConfigProperty.compareConfig"}}
{{#unless view.serviceConfigProperty.compareConfig.isMock}}
- <span>
- <strong><i class="icon-asterisks">✵</i>{{view.serviceConfigProperty.compareConfig.serviceVersion.author}}</strong>
- {{t dashboard.configHistory.info-bar.authoredOn}}
- <strong>{{view.serviceConfigProperty.compareConfig.serviceVersion.modifiedDate}}</strong>
- </span>
+ <span class="label label-info">{{view.serviceConfigProperty.compareConfig.serviceVersion.versionText}}</span>
{{/unless}}
</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/2a617da8/ambari-web/app/templates/common/configs/config_history_flow.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/configs/config_history_flow.hbs b/ambari-web/app/templates/common/configs/config_history_flow.hbs
index 70acde3..7f80c7a 100644
--- a/ambari-web/app/templates/common/configs/config_history_flow.hbs
+++ b/ambari-web/app/templates/common/configs/config_history_flow.hbs
@@ -19,24 +19,26 @@
<div id="config_history_flow">
<div class="version-slider">
- <div {{bindAttr class=":pull-left :arrow-left :visibleArrow view.showLeftArrow::hide"}} {{action shiftBack target="view"}}></div>
- {{#each serviceVersion in view.visibleServiceVersion}}
- <div {{bindAttr class=":flow-element :pull-left serviceVersion.first:first"}}>
- <div class="arrow-box pull-left"><div class="big-arrow-right"></div></div>
- <div {{bindAttr class=":box :pull-right serviceVersion.isDisplayed:displayed"}}>
- <div class="top-right-label">{{serviceVersion.version}}</div>
- <p class="date">{{serviceVersion.shortModifiedDate}}</p>
- <p class="content">{{serviceVersion.author}}: {{serviceVersion.briefNotes}}</p>
- {{#if serviceVersion.isCurrent}}
- <div class="current-label label label-success">
- {{t common.latest}}
- <i {{bindAttr class=":icon-refresh :restart-required-service view.displayedServiceVersion.isRestartRequired::hidden"}}></i>
- </div>
- {{/if}}
- </div>
+ <div {{bindAttr class=":icon-chevron-box :pull-left view.showLeftArrow::hide"}} {{action shiftBack target="view"}}><i class="icon-chevron-left icon-3x"></i></div>
+ {{#each serviceVersion in view.visibleServiceVersion}}
+ <div {{bindAttr class=":flow-element :pull-left serviceVersion.first:first"}}>
+ <div class="arrow-box pull-left"><i class="icon-arrow-right icon-3x"></i></div>
+ <div {{bindAttr class=":box :pull-right serviceVersion.isDisplayed:displayed"}}>
+ <div class="top-label">
+ <span class="label label-info">{{serviceVersion.versionText}}</span>
+ {{#if serviceVersion.isCurrent}}
+ <span class="label label-success">
+ {{t common.current}}
+ <i {{bindAttr class=":icon-refresh :restart-required-service view.displayedServiceVersion.isRestartRequired::hidden"}}></i>
+ </span>
+ {{/if}}
</div>
- {{/each}}
- <div {{bindAttr class=":arrow-right :visibleArrow view.showRightArrow::hide"}} {{action shiftForward target="view"}}></div>
+ <div class="content">{{serviceVersion.author}}</div>
+ <div class="content">{{serviceVersion.shortModifiedDate}}</div>
+ </div>
+ </div>
+ {{/each}}
+ <div {{bindAttr class=":icon-chevron-box :pull-right view.showRightArrow::hide"}} {{action shiftForward target="view"}}><i class="icon-chevron-right icon-3x"></i></div>
</div>
<div class="version-info-bar">
<div class="row-fluid">
@@ -49,10 +51,9 @@
{{#each serviceVersion in view.dropDownList}}
<li class="pointer dropdown-submenu">
<div class="row-fluid">
- <div class="span2">{{t common.version}}: {{serviceVersion.version}}</div>
- <div class="span3">{{serviceVersion.modifiedDate}}</div>
- <div class="span2">{{serviceVersion.author}}</div>
- <div class="span4"><span class="ellipsis">{{t dashboard.configHistory.info-bar.changesToHandle}}</span></div>
+ <div class="span2">{{serviceVersion.versionText}}</div>
+ <div class="span6">{{serviceVersion.modifiedDate}}</div>
+ <div class="span3">{{serviceVersion.author}}</div>
<div class="pull-right"><i class="icon-caret-right"></i></div>
</div>
<ul class="dropdown-menu">
@@ -73,7 +74,10 @@
</ul>
</div>
<div class="label-wrapper span8">
- <span {{bindAttr class=":label view.displayedServiceVersion.isCurrent:label-success"}}>{{t common.latest}}: {{view.displayedServiceVersion.version}}</span>
+ <span class="label label-info">{{view.displayedServiceVersion.versionText}}</span>
+ {{#if view.displayedServiceVersion.isCurrent}}
+ <span class="label label-success">{{t common.current}}</span>
+ {{/if}}
<strong>{{view.displayedServiceVersion.author}}</strong> {{t dashboard.configHistory.info-bar.authoredOn}} <strong>{{view.displayedServiceVersion.modifiedDate}}</strong>
</div>
<div class="pull-right">
http://git-wip-us.apache.org/repos/asf/ambari/blob/2a617da8/ambari-web/app/templates/main/dashboard/config_history.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/dashboard/config_history.hbs b/ambari-web/app/templates/main/dashboard/config_history.hbs
index 6306078..dc7dd22 100644
--- a/ambari-web/app/templates/main/dashboard/config_history.hbs
+++ b/ambari-web/app/templates/main/dashboard/config_history.hbs
@@ -38,11 +38,16 @@
{{#if view.pageContent}}
{{#each item in view.pageContent}}
<tr>
- <td class="first"><a {{action goToServiceConfigs item.serviceName}}>
- {{item.serviceVersion}}
- {{#if item.isCurrent}} ({{t common.latest}}){{/if}}
- <i {{bindAttr class=":icon-refresh :restart-required-service item.isRestartRequired::hidden"}}></i>
- </a></td>
+ <td class="first">
+ <a {{action goToServiceConfigs item.serviceName}}>
+ {{item.serviceName}}
+ </a>
+ <span class="label label-info">{{item.versionText}}</span>
+ {{#if item.isCurrent}}
+ <span class="label label-success">{{t common.current}}</span>
+ {{/if}}
+ <i {{bindAttr class=":icon-refresh :restart-required-service item.isRestartRequired::hidden"}}></i>
+ </td>
<td>{{item.modifiedDate}}</td>
<td>{{item.author}}</td>
<td>{{item.notes}}</td>
http://git-wip-us.apache.org/repos/asf/ambari/blob/2a617da8/ambari-web/app/views/common/configs/config_history_flow.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/configs/config_history_flow.js b/ambari-web/app/views/common/configs/config_history_flow.js
index 9521eab..2b305b5 100644
--- a/ambari-web/app/views/common/configs/config_history_flow.js
+++ b/ambari-web/app/views/common/configs/config_history_flow.js
@@ -101,7 +101,9 @@ App.ConfigHistoryFlowView = Em.View.extend({
var startIndex = 0;
serviceVersions.setEach('isDisplayed', false);
- serviceVersions.findProperty('isCurrent').set('isDisplayed', true);
+ if (serviceVersions.findProperty('isCurrent')) {
+ serviceVersions.findProperty('isCurrent').set('isDisplayed', true);
+ }
if (serviceVersions.length > 0) {
if (serviceVersions.length > this.VERSIONS_IN_FLOW) {
http://git-wip-us.apache.org/repos/asf/ambari/blob/2a617da8/ambari-web/app/views/main/dashboard/config_history_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/dashboard/config_history_view.js b/ambari-web/app/views/main/dashboard/config_history_view.js
index 1c6105b..8c68477 100644
--- a/ambari-web/app/views/main/dashboard/config_history_view.js
+++ b/ambari-web/app/views/main/dashboard/config_history_view.js
@@ -151,7 +151,6 @@ App.MainConfigHistoryView = App.TableView.extend({
updateFilter: function (iColumn, value, type) {
var self = this;
-
this.set('controller.resetStartIndex', false);
this.saveFilterConditions(iColumn, value, type, false);
if (!this.get('filteringComplete')) {