| /** |
| * 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.view; |
| |
| import javax.inject.Inject; |
| import javax.inject.Provider; |
| import javax.inject.Singleton; |
| import javax.xml.bind.JAXBException; |
| |
| import java.beans.IntrospectionException; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.MalformedURLException; |
| import java.nio.file.Path; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.LinkedBlockingQueue; |
| import java.util.concurrent.ThreadPoolExecutor; |
| import java.util.concurrent.TimeUnit; |
| |
| import org.apache.ambari.server.AmbariException; |
| import org.apache.ambari.server.ClusterNotFoundException; |
| import org.apache.ambari.server.api.resources.ResourceInstanceFactoryImpl; |
| import org.apache.ambari.server.api.resources.SubResourceDefinition; |
| import org.apache.ambari.server.api.resources.ViewExternalSubResourceDefinition; |
| import org.apache.ambari.server.api.services.AmbariMetaInfo; |
| import org.apache.ambari.server.api.services.ViewExternalSubResourceService; |
| import org.apache.ambari.server.api.services.ViewSubResourceService; |
| import org.apache.ambari.server.configuration.ComponentSSLConfiguration; |
| import org.apache.ambari.server.configuration.Configuration; |
| import org.apache.ambari.server.controller.AmbariServer; |
| import org.apache.ambari.server.controller.AmbariSessionManager; |
| import org.apache.ambari.server.controller.spi.Resource; |
| import org.apache.ambari.server.controller.spi.ResourceProvider; |
| import org.apache.ambari.server.events.ServiceInstalledEvent; |
| import org.apache.ambari.server.events.publishers.AmbariEventPublisher; |
| import org.apache.ambari.server.orm.dao.MemberDAO; |
| 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.RemoteAmbariClusterDAO; |
| 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; |
| import org.apache.ambari.server.orm.entities.GroupEntity; |
| import org.apache.ambari.server.orm.entities.MemberEntity; |
| import org.apache.ambari.server.orm.entities.PermissionEntity; |
| import org.apache.ambari.server.orm.entities.PrincipalEntity; |
| import org.apache.ambari.server.orm.entities.PrivilegeEntity; |
| import org.apache.ambari.server.orm.entities.RemoteAmbariClusterEntity; |
| import org.apache.ambari.server.orm.entities.ResourceEntity; |
| import org.apache.ambari.server.orm.entities.ResourceTypeEntity; |
| import org.apache.ambari.server.orm.entities.UserEntity; |
| import org.apache.ambari.server.orm.entities.ViewEntity; |
| import org.apache.ambari.server.orm.entities.ViewEntityEntity; |
| import org.apache.ambari.server.orm.entities.ViewInstanceDataEntity; |
| import org.apache.ambari.server.orm.entities.ViewInstanceEntity; |
| import org.apache.ambari.server.orm.entities.ViewParameterEntity; |
| import org.apache.ambari.server.orm.entities.ViewResourceEntity; |
| import org.apache.ambari.server.security.SecurityHelper; |
| import org.apache.ambari.server.security.authorization.AuthorizationHelper; |
| import org.apache.ambari.server.security.authorization.ClusterInheritedPermissionHelper; |
| import org.apache.ambari.server.security.authorization.ResourceType; |
| import org.apache.ambari.server.security.authorization.RoleAuthorization; |
| import org.apache.ambari.server.state.Clusters; |
| import org.apache.ambari.server.state.StackId; |
| import org.apache.ambari.server.state.stack.OsFamily; |
| import org.apache.ambari.server.utils.VersionUtils; |
| import org.apache.ambari.server.view.configuration.AutoInstanceConfig; |
| import org.apache.ambari.server.view.configuration.EntityConfig; |
| import org.apache.ambari.server.view.configuration.InstanceConfig; |
| import org.apache.ambari.server.view.configuration.ParameterConfig; |
| import org.apache.ambari.server.view.configuration.PermissionConfig; |
| import org.apache.ambari.server.view.configuration.PersistenceConfig; |
| import org.apache.ambari.server.view.configuration.PropertyConfig; |
| import org.apache.ambari.server.view.configuration.ResourceConfig; |
| import org.apache.ambari.server.view.configuration.ViewConfig; |
| import org.apache.ambari.server.view.validation.ValidationException; |
| import org.apache.ambari.view.AmbariStreamProvider; |
| import org.apache.ambari.view.ClusterType; |
| import org.apache.ambari.view.Masker; |
| import org.apache.ambari.view.SystemException; |
| import org.apache.ambari.view.View; |
| import org.apache.ambari.view.ViewContext; |
| import org.apache.ambari.view.ViewDefinition; |
| import org.apache.ambari.view.ViewInstanceDefinition; |
| import org.apache.ambari.view.ViewResourceHandler; |
| import org.apache.ambari.view.cluster.Cluster; |
| import org.apache.ambari.view.events.Event; |
| import org.apache.ambari.view.events.Listener; |
| import org.apache.ambari.view.migration.ViewDataMigrationException; |
| import org.apache.ambari.view.validation.Validator; |
| import org.apache.log4j.PropertyConfigurator; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.xml.sax.SAXException; |
| |
| import com.google.common.collect.FluentIterable; |
| import com.google.common.collect.Sets; |
| import com.google.common.eventbus.AllowConcurrentEvents; |
| import com.google.common.eventbus.Subscribe; |
| import com.google.inject.AbstractModule; |
| import com.google.inject.Guice; |
| import com.google.inject.Injector; |
| import com.google.inject.persist.Transactional; |
| |
| /** |
| * Registry for view and view instance definitions. |
| */ |
| @Singleton |
| public class ViewRegistry { |
| |
| /** |
| * Constants |
| */ |
| private static final String EXTRACTED_ARCHIVES_DIR = "work"; |
| private static final String EXTRACT_COMMAND = "extract"; |
| private static final String ALL_VIEWS_REG_EXP = ".*"; |
| protected static final int DEFAULT_REQUEST_CONNECT_TIMEOUT = 5000; |
| protected static final int DEFAULT_REQUEST_READ_TIMEOUT = 10000; |
| private static final String VIEW_AMBARI_VERSION_REGEXP = "^((\\d+\\.)?)*(\\*|\\d+)$"; |
| private static final String VIEW_LOG_FILE = "view.log4j.properties"; |
| private static final String AMBARI_LOG_FILE = "log4j.properties"; |
| private static final String LOG4J = "log4j."; |
| |
| public static final String API_PREFIX = "/api/v1/clusters/"; |
| |
| /** |
| * Thread pool |
| */ |
| private static ExecutorService executorService; |
| |
| /** |
| * Mapping of view names to view definitions. |
| */ |
| private Map<String, ViewEntity> viewDefinitions = new HashMap<String, ViewEntity>(); |
| |
| /** |
| * Mapping of view instances to view definition and instance name. |
| */ |
| private Map<ViewEntity, Map<String, ViewInstanceEntity>> viewInstanceDefinitions = |
| new HashMap<ViewEntity, Map<String, ViewInstanceEntity>>(); |
| |
| /** |
| * Mapping of view names to sub-resources. |
| */ |
| private final Map<String, Set<SubResourceDefinition>> subResourceDefinitionsMap = |
| new ConcurrentHashMap<String, Set<SubResourceDefinition>>(); |
| |
| /** |
| * Mapping of view types to resource providers. |
| */ |
| private final Map<Resource.Type, ResourceProvider> resourceProviders = |
| new ConcurrentHashMap<Resource.Type, ResourceProvider>(); |
| |
| /** |
| * Mapping of view names to registered listeners. |
| */ |
| private final Map<String, Set<Listener>> listeners = |
| new ConcurrentHashMap<String, Set<Listener>>(); |
| |
| /** |
| * The singleton view registry instance. |
| */ |
| private static ViewRegistry singleton; |
| |
| /** |
| * The logger. |
| */ |
| protected final static Logger LOG = LoggerFactory.getLogger(ViewRegistry.class); |
| |
| /** |
| * View Data Migration Utility |
| */ |
| protected ViewDataMigrationUtility viewDataMigrationUtility; |
| |
| /** |
| * View data access object. |
| */ |
| @Inject |
| ViewDAO viewDAO; |
| |
| /** |
| * View instance data access object. |
| */ |
| @Inject |
| ViewInstanceDAO instanceDAO; |
| |
| /** |
| * User data access object. |
| */ |
| @Inject |
| UserDAO userDAO; |
| |
| /** |
| * Group member data access object. |
| */ |
| @Inject |
| MemberDAO memberDAO; |
| |
| /** |
| * Privilege data access object. |
| */ |
| @Inject |
| PrivilegeDAO privilegeDAO; |
| |
| /** |
| * Helper with security related utilities. |
| */ |
| @Inject |
| SecurityHelper securityHelper; |
| |
| /** |
| * Resource data access object. |
| */ |
| @Inject |
| ResourceDAO resourceDAO; |
| |
| /** |
| * Resource type data access object. |
| */ |
| @Inject |
| ResourceTypeDAO resourceTypeDAO; |
| |
| /** |
| * Principal data access object. |
| */ |
| @Inject |
| PrincipalDAO principalDAO; |
| |
| /** |
| * Permission data access objects |
| */ |
| @Inject |
| PermissionDAO permissionDAO; |
| |
| /** |
| * The Ambari managed clusters. |
| */ |
| @Inject |
| Provider<Clusters> clustersProvider; |
| |
| /** |
| * Ambari meta info. |
| */ |
| @Inject |
| Provider<AmbariMetaInfo> ambariMetaInfoProvider; |
| |
| /** |
| * Ambari configuration. |
| */ |
| @Inject |
| Configuration configuration; |
| |
| /** |
| * The handler list. |
| */ |
| @Inject |
| ViewInstanceHandlerList handlerList; |
| |
| /** |
| * The view extractor; |
| */ |
| @Inject |
| ViewExtractor extractor; |
| |
| /** |
| * The view archive utility. |
| */ |
| @Inject |
| ViewArchiveUtility archiveUtility; |
| |
| /** |
| * The Ambari session manager. |
| */ |
| @Inject |
| AmbariSessionManager ambariSessionManager; |
| |
| /** |
| * Registry for Remote Ambari Cluster |
| */ |
| @Inject |
| RemoteAmbariClusterRegistry remoteAmbariClusterRegistry; |
| |
| /** |
| * Remote Ambari Cluster Dao |
| */ |
| @Inject |
| RemoteAmbariClusterDAO remoteAmbariClusterDAO; |
| |
| // ----- Constructors ----------------------------------------------------- |
| |
| /** |
| * Create the view registry. |
| */ |
| @Inject |
| public ViewRegistry(AmbariEventPublisher publisher) { |
| publisher.register(this); |
| } |
| |
| |
| // ----- ViewRegistry ------------------------------------------------------ |
| |
| /** |
| * Registry main method. |
| * |
| * @param args the command line arguments |
| */ |
| public static void main(String[] args) { |
| |
| if (args.length >= 2) { |
| |
| if (args[0].equals(EXTRACT_COMMAND)) { |
| |
| String archivePath = args[1]; |
| ViewModule viewModule = new ViewModule(); |
| |
| try { |
| if (extractViewArchive(archivePath, viewModule, true)) { |
| System.exit(0); |
| } |
| } catch (Exception e) { |
| String msg = "Caught exception extracting view archive " + archivePath + "."; |
| LOG.error(msg, e); |
| System.exit(2); |
| } |
| } |
| } |
| System.exit(1); |
| } |
| |
| /** |
| * Get the collection of all the view definitions. |
| * |
| * @return the collection of view definitions |
| */ |
| public Collection<ViewEntity> getDefinitions() { |
| return viewDefinitions.values(); |
| } |
| |
| /** |
| * Get a view definition for the given name. |
| * |
| * @param viewName the view name |
| * @param version the version |
| * |
| * @return the view definition for the given name |
| */ |
| public ViewEntity getDefinition(String viewName, String version) { |
| return getDefinition(ViewEntity.getViewName(viewName, version)); |
| } |
| |
| /** |
| * Get the view definition for the given resource type. |
| * |
| * @param resourceTypeEntity the resource type |
| * |
| * @return the view definition for the given resource type or null |
| */ |
| public ViewEntity getDefinition(ResourceTypeEntity resourceTypeEntity) { |
| |
| for (ViewEntity viewEntity : viewDefinitions.values()) { |
| if (viewEntity.isDeployed()) { |
| if (viewEntity.getResourceType().equals(resourceTypeEntity)) { |
| return viewEntity; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Add a view definition to the registry. |
| * |
| * @param definition the definition |
| */ |
| public void addDefinition(ViewEntity definition) { |
| viewDefinitions.put(definition.getName(), definition); |
| } |
| |
| /** |
| * Get the collection of view instances for the given view definition. |
| * |
| * @param definition the view definition |
| * |
| * @return the collection of view instances for the view definition |
| */ |
| public Collection<ViewInstanceEntity> getInstanceDefinitions(ViewEntity definition) { |
| if (definition != null) { |
| Map<String, ViewInstanceEntity> instanceEntityMap = viewInstanceDefinitions.get(definition); |
| if (instanceEntityMap != null) { |
| return instanceEntityMap.values(); |
| } |
| } |
| return Collections.emptyList(); |
| } |
| |
| /** |
| * Get the instance definition for the given view name and instance name. |
| * |
| * @param viewName the view name |
| * @param version the version |
| * @param instanceName the instance name |
| * |
| * @return the view instance definition for the given view and instance name |
| */ |
| public ViewInstanceEntity getInstanceDefinition(String viewName, String version, String instanceName) { |
| Map<String, ViewInstanceEntity> viewInstanceDefinitionMap = |
| viewInstanceDefinitions.get(getDefinition(viewName, version)); |
| |
| return viewInstanceDefinitionMap == null ? null : viewInstanceDefinitionMap.get(instanceName); |
| } |
| |
| /** |
| * Add an instance definition for the given view definition. |
| * |
| * @param definition the owning view definition |
| * @param instanceDefinition the instance definition |
| */ |
| public void addInstanceDefinition(ViewEntity definition, ViewInstanceEntity instanceDefinition) { |
| Map<String, ViewInstanceEntity> instanceDefinitions = viewInstanceDefinitions.get(definition); |
| if (instanceDefinitions == null) { |
| instanceDefinitions = new HashMap<String, ViewInstanceEntity>(); |
| viewInstanceDefinitions.put(definition, instanceDefinitions); |
| } |
| |
| View view = definition.getView(); |
| if (view != null) { |
| view.onCreate(instanceDefinition); |
| } |
| instanceDefinitions.put(instanceDefinition.getName(), instanceDefinition); |
| } |
| |
| /** |
| * Remove an instance definition for the given view definition. |
| * |
| * @param definition the owning view definition |
| * @param instanceName the instance name |
| */ |
| public void removeInstanceDefinition(ViewEntity definition, String instanceName) { |
| Map<String, ViewInstanceEntity> instanceDefinitions = viewInstanceDefinitions.get(definition); |
| if (instanceDefinitions != null) { |
| |
| ViewInstanceEntity instanceDefinition = instanceDefinitions.get(instanceName); |
| if (instanceDefinition != null) { |
| View view = definition.getView(); |
| if (view != null) { |
| view.onDestroy(instanceDefinition); |
| } |
| instanceDefinitions.remove(instanceName); |
| } |
| } |
| } |
| |
| /** |
| * Init the singleton instance. |
| * |
| * @param singleton the view registry |
| */ |
| public static void initInstance(ViewRegistry singleton) { |
| ViewRegistry.singleton = singleton; |
| } |
| |
| /** |
| * Get the view registry singleton. |
| * |
| * @return the view registry |
| */ |
| public static ViewRegistry getInstance() { |
| return singleton; |
| } |
| |
| /** |
| * Get the sub-resource definitions for the given view name. |
| * |
| * @param viewName the instance name |
| * @param version the version |
| * |
| * @return the set of sub-resource definitions |
| */ |
| public Set<SubResourceDefinition> getSubResourceDefinitions( |
| String viewName, String version) { |
| |
| |
| viewName = ViewEntity.getViewName(viewName, version); |
| |
| return subResourceDefinitionsMap.get(viewName); |
| } |
| /** |
| * Read all view archives. |
| */ |
| public void readViewArchives() { |
| readViewArchives(false, false, ALL_VIEWS_REG_EXP); |
| } |
| |
| /** |
| * Read only view archives with names corresponding to given regular expression. |
| * |
| * @param viewNameRegExp view name regular expression |
| */ |
| public void readViewArchives(String viewNameRegExp) { |
| readViewArchives(false, false, viewNameRegExp); |
| } |
| |
| /** |
| * Determine whether or not the given view instance exists. |
| * |
| * @param instanceEntity the view instance entity |
| * |
| * @return true if the the given view instance exists; false otherwise |
| */ |
| public boolean instanceExists(ViewInstanceEntity instanceEntity) { |
| |
| ViewEntity viewEntity = getDefinition(instanceEntity.getViewName()); |
| |
| return viewEntity != null && |
| (getInstanceDefinition(viewEntity.getCommonName(), viewEntity.getVersion(), instanceEntity.getName()) != null); |
| } |
| |
| /** |
| * Install the given view instance with its associated view. |
| * |
| * @param instanceEntity the view instance entity |
| * |
| * @throws ValidationException if the given instance fails the validation checks |
| * @throws IllegalArgumentException if the view associated with the given instance |
| * does not exist |
| * @throws SystemException if the instance can not be installed |
| */ |
| public void installViewInstance(ViewInstanceEntity instanceEntity) |
| throws ValidationException, IllegalArgumentException, SystemException { |
| ViewEntity viewEntity = getDefinition(instanceEntity.getViewName()); |
| |
| if (viewEntity != null) { |
| String instanceName = instanceEntity.getName(); |
| String viewName = viewEntity.getCommonName(); |
| String version = viewEntity.getVersion(); |
| |
| if (getInstanceDefinition(viewName, version, instanceName) == null) { |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("Creating view instance " + viewName + "/" + |
| version + "/" + instanceName); |
| } |
| |
| instanceEntity.validate(viewEntity, Validator.ValidationContext.PRE_CREATE); |
| |
| setPersistenceEntities(instanceEntity); |
| |
| ViewInstanceEntity persistedInstance = mergeViewInstance(instanceEntity, viewEntity.getResourceType()); |
| |
| instanceEntity.setViewInstanceId(persistedInstance.getViewInstanceId()); |
| syncViewInstance(instanceEntity, persistedInstance); |
| |
| try { |
| // bind the view instance to a view |
| bindViewInstance(viewEntity, instanceEntity); |
| } catch (Exception e) { |
| String message = "Caught exception installing view instance."; |
| LOG.error(message, e); |
| throw new IllegalStateException(message, e); |
| } |
| // update the registry |
| addInstanceDefinition(viewEntity, instanceEntity); |
| |
| // add the web app context |
| handlerList.addViewInstance(instanceEntity); |
| } |
| } else { |
| String message = "Attempt to install an instance for an unknown view " + |
| instanceEntity.getViewName() + "."; |
| |
| LOG.error(message); |
| throw new IllegalArgumentException(message); |
| } |
| } |
| |
| /** |
| * Update a view instance for the view with the given view name. |
| * |
| * @param instanceEntity the view instance entity |
| * |
| * @throws ValidationException if the given instance fails the validation checks |
| * @throws SystemException if the instance can not be updated |
| */ |
| public void updateViewInstance(ViewInstanceEntity instanceEntity) |
| throws ValidationException, SystemException { |
| ViewEntity viewEntity = getDefinition(instanceEntity.getViewName()); |
| |
| if (viewEntity != null) { |
| instanceEntity.validate(viewEntity, Validator.ValidationContext.PRE_UPDATE); |
| instanceDAO.merge(instanceEntity); |
| |
| syncViewInstance(instanceEntity); |
| } |
| } |
| |
| /** |
| * Calls onUpdate hook on View class |
| * |
| * @param instanceEntity |
| */ |
| public void updateView(ViewInstanceEntity instanceEntity){ |
| ViewEntity viewEntity = getDefinition(instanceEntity.getViewName()); |
| if(null != viewEntity && null != viewEntity.getView()){ |
| viewEntity.getView().onUpdate(instanceEntity); |
| } |
| } |
| |
| /** |
| * Get a view instance entity for the given view name and instance name. |
| * |
| * @param viewName the view name |
| * @param instanceName the instance name |
| * |
| * @return a view instance entity for the given view name and instance name. |
| */ |
| public ViewInstanceEntity getViewInstanceEntity(String viewName, String instanceName) { |
| return instanceDAO.findByName(viewName, instanceName); |
| } |
| |
| /** |
| * 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 |
| */ |
| @Transactional |
| public void uninstallViewInstance(ViewInstanceEntity instanceEntity) throws IllegalStateException { |
| ViewEntity viewEntity = getDefinition(instanceEntity.getViewName()); |
| |
| if (viewEntity != null) { |
| String instanceName = instanceEntity.getName(); |
| String viewName = viewEntity.getCommonName(); |
| 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); |
| } |
| List<PrivilegeEntity> instancePrivileges = privilegeDAO.findByResourceId(instanceEntity.getResource().getId()); |
| for (PrivilegeEntity privilegeEntity : instancePrivileges) { |
| removePrivilegeEntity(privilegeEntity); |
| } |
| instanceDAO.remove(instanceEntity); |
| viewEntity.removeInstanceDefinition(instanceName); |
| removeInstanceDefinition(viewEntity, instanceName); |
| |
| // remove the web app context |
| handlerList.removeViewInstance(instanceEntity); |
| } |
| } |
| } |
| |
| /** |
| * Remove the data entry keyed by the given key from the given instance entity. |
| * |
| * @param instanceEntity the instance entity |
| * @param key the data key |
| */ |
| @Transactional |
| public void removeInstanceData(ViewInstanceEntity instanceEntity, String key) { |
| ViewInstanceDataEntity dataEntity = instanceEntity.getInstanceData(key); |
| if (dataEntity != null) { |
| instanceDAO.removeData(dataEntity); |
| } |
| instanceEntity.removeInstanceData(key); |
| instanceDAO.merge(instanceEntity); |
| } |
| |
| /** |
| * Copy all privileges from one view instance to another |
| * |
| * @param sourceInstanceEntity the source instance entity |
| * @param targetInstanceEntity the target instance entity |
| */ |
| @Transactional |
| public void copyPrivileges(ViewInstanceEntity sourceInstanceEntity, |
| ViewInstanceEntity targetInstanceEntity) { |
| LOG.debug("Copy all privileges from " + sourceInstanceEntity.getName() + " to " + |
| targetInstanceEntity.getName()); |
| List<PrivilegeEntity> targetInstancePrivileges = privilegeDAO.findByResourceId(targetInstanceEntity.getResource().getId()); |
| if (targetInstancePrivileges.size() > 0) { |
| LOG.warn("Old privileges will be removed for " + targetInstanceEntity.getName()); |
| for (PrivilegeEntity privilegeEntity : targetInstancePrivileges) { |
| removePrivilegeEntity(privilegeEntity); |
| } |
| } |
| |
| List<PrivilegeEntity> sourceInstancePrivileges = privilegeDAO.findByResourceId(sourceInstanceEntity.getResource().getId()); |
| for (PrivilegeEntity sourcePrivilege : sourceInstancePrivileges) { |
| PrivilegeEntity targetPrivilege = new PrivilegeEntity(); |
| targetPrivilege.setPrincipal(sourcePrivilege.getPrincipal()); |
| targetPrivilege.setResource(targetInstanceEntity.getResource()); |
| targetPrivilege.setPermission(sourcePrivilege.getPermission()); |
| privilegeDAO.create(targetPrivilege); |
| |
| targetPrivilege.getPrincipal().getPrivileges().add(sourcePrivilege); |
| } |
| } |
| |
| /** |
| * Notify any registered listeners of the given event. |
| * |
| * @param event the event |
| */ |
| public void fireEvent(Event event) { |
| |
| ViewDefinition subject = event.getViewSubject(); |
| |
| fireEvent(event, subject.getViewName()); |
| fireEvent(event, ViewEntity.getViewName(subject.getViewName(), subject.getVersion())); |
| } |
| |
| /** |
| * Register the given listener to listen for events from the view identified by the given name and version. |
| * |
| * @param listener the listener |
| * @param viewName the view name |
| * @param viewVersion the view version; null indicates all versions |
| */ |
| public synchronized void registerListener(Listener listener, String viewName, String viewVersion) { |
| |
| String name = viewVersion == null ? viewName : ViewEntity.getViewName(viewName, viewVersion); |
| |
| Set<Listener> listeners = this.listeners.get(name); |
| |
| if (listeners == null) { |
| listeners = Sets.newSetFromMap(new ConcurrentHashMap<Listener, Boolean>()); |
| this.listeners.put(name, listeners); |
| } |
| |
| listeners.add(listener); |
| } |
| |
| /** |
| * Un-register the given listener from the view identified by the given name and version. |
| * |
| * @param listener the listener |
| * @param viewName the view name |
| * @param viewVersion the view version; null indicates all versions |
| */ |
| public synchronized void unregisterListener(Listener listener, String viewName, String viewVersion) { |
| |
| String name = viewVersion == null ? viewName : ViewEntity.getViewName(viewName, viewVersion); |
| |
| Set<Listener> listeners = this.listeners.get(name); |
| |
| if (listeners != null) { |
| listeners.remove(listener); |
| } |
| } |
| |
| /** |
| * Determine whether or not the access specified by the given permission |
| * is permitted for the given user on the view instance identified by |
| * the given resource. |
| * |
| * @param permissionEntity the permission entity |
| * @param resourceEntity the resource entity |
| * @param userName the user name |
| * |
| * @return true if the access specified by the given permission |
| * is permitted for the given user. |
| */ |
| public boolean hasPermission(PermissionEntity permissionEntity, ResourceEntity resourceEntity, String userName) { |
| |
| UserEntity userEntity = userDAO.findUserByName(userName); |
| |
| if (userEntity == null) { |
| return false; |
| } |
| |
| if (privilegeDAO.exists(userEntity.getPrincipal(), resourceEntity, permissionEntity)) { |
| return true; |
| } |
| |
| List<MemberEntity> memberEntities = memberDAO.findAllMembersByUser(userEntity); |
| |
| for (MemberEntity memberEntity : memberEntities) { |
| |
| GroupEntity groupEntity = memberEntity.getGroup(); |
| |
| if (privilegeDAO.exists(groupEntity.getPrincipal(), resourceEntity, permissionEntity)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Determine whether or not access to the view instance resource identified |
| * by the given instance name should be allowed based on the permissions |
| * granted to the current user. |
| * |
| * @param viewName the view name |
| * @param version the view version |
| * @param instanceName the name of the view instance resource |
| * @param readOnly indicate whether or not this is for a read only operation |
| * |
| * @return true if the access to the view instance is allowed |
| */ |
| public boolean checkPermission(String viewName, String version, String instanceName, boolean readOnly) { |
| |
| ViewInstanceEntity instanceEntity = |
| instanceName == null ? null : getInstanceDefinition(viewName, version, instanceName); |
| |
| return checkPermission(instanceEntity, readOnly); |
| } |
| |
| /** |
| * Determine whether or not access to the given view instance should be allowed based |
| * on the permissions granted to the current user. |
| * |
| * @param instanceEntity the view instance entity |
| * @param readOnly indicate whether or not this is for a read only operation |
| * |
| * @return true if the access to the view instance is allowed |
| */ |
| public boolean checkPermission(ViewInstanceEntity instanceEntity, boolean readOnly) { |
| |
| ResourceEntity resourceEntity = instanceEntity == null ? null : instanceEntity.getResource(); |
| |
| return (resourceEntity == null && readOnly) || checkAuthorization(resourceEntity); |
| } |
| |
| /** |
| * Determine whether or not the current view user has admin rights. |
| * |
| * @return true if the current view user is an admin |
| */ |
| public boolean checkAdmin() { |
| return checkAuthorization(null); |
| } |
| |
| /** |
| * 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 |
| * |
| * @return true if the view instance should be included based on the permissions of the current user |
| */ |
| public boolean includeDefinition(ViewEntity definitionEntity) { |
| |
| if (checkPermission(null, false)) { |
| return true; |
| } |
| |
| for (ViewInstanceEntity instanceEntity: definitionEntity.getInstances()) { |
| if (checkPermission(instanceEntity, true) ) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Set the properties of the given view instance from the given property set. |
| * |
| * @param instanceEntity the view instance entity |
| * @param properties the view instance properties |
| * @param viewConfig the view configuration |
| * @param classLoader the class loader for the view |
| * |
| * @throws SystemException if the view instance properties can not be set |
| */ |
| public void setViewInstanceProperties(ViewInstanceEntity instanceEntity, Map<String, String> properties, |
| ViewConfig viewConfig, ClassLoader classLoader) throws SystemException { |
| try { |
| Masker masker = getMasker(viewConfig.getMaskerClass(classLoader)); |
| |
| Map<String, ParameterConfig> parameterConfigMap = new HashMap<String, ParameterConfig>(); |
| for (ParameterConfig paramConfig : viewConfig.getParameters()) { |
| parameterConfigMap.put(paramConfig.getName(), paramConfig); |
| } |
| for (Map.Entry<String, String> entry : properties.entrySet()) { |
| String name = entry.getKey(); |
| String value = entry.getValue(); |
| |
| ParameterConfig parameterConfig = parameterConfigMap.get(name); |
| |
| if (parameterConfig != null && parameterConfig.isMasked()) { |
| value = masker.mask(value); |
| } |
| instanceEntity.putProperty(name, value); |
| } |
| } catch (Exception e) { |
| throw new SystemException("Caught exception while setting instance property.", e); |
| } |
| } |
| |
| /** |
| * Get the cluster associated with the given view instance. |
| * |
| * @param viewInstance the view instance |
| * |
| * @return the cluster |
| */ |
| public Cluster getCluster(ViewInstanceDefinition viewInstance) { |
| if (viewInstance != null) { |
| Long clusterId = viewInstance.getClusterHandle(); |
| |
| if (clusterId != null && viewInstance.getClusterType() == ClusterType.LOCAL_AMBARI) { |
| try { |
| return new ClusterImpl(clustersProvider.get().getCluster(clusterId)); |
| } catch (AmbariException e) { |
| LOG.error("Could not find the cluster identified by {}.", clusterId); |
| throw new IllegalClusterException(e); |
| } |
| |
| } else if (clusterId != null && viewInstance.getClusterType() == ClusterType.REMOTE_AMBARI) { |
| try { |
| return remoteAmbariClusterRegistry.get(clusterId); |
| } catch (MalformedURLException e) { |
| LOG.error("Remote Cluster with id={} had invalid URL.", clusterId, e); |
| throw new IllegalClusterException(e); |
| } catch (ClusterNotFoundException e) { |
| LOG.error("Cannot get Remote Cluster with id={}.", clusterId, e); |
| throw new IllegalClusterException(e); |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Receive notification that a new service has been added to a cluster. |
| * </p> |
| * Used for view instance auto creation. |
| * |
| * @param event the service installed event |
| */ |
| @Subscribe |
| @AllowConcurrentEvents |
| public void onAmbariEvent(ServiceInstalledEvent event) { |
| |
| Clusters clusters = clustersProvider.get(); |
| Long clusterId = event.getClusterId(); |
| |
| try { |
| org.apache.ambari.server.state.Cluster cluster = clusters.getClusterById(clusterId); |
| String clusterName = cluster.getClusterName(); |
| |
| StackId stackId = cluster.getCurrentStackVersion(); |
| Set<String> serviceNames = cluster.getServices().keySet(); |
| |
| for (ViewEntity viewEntity : getDefinitions()) { |
| |
| String viewName = viewEntity.getName(); |
| ViewConfig viewConfig = viewEntity.getConfiguration(); |
| AutoInstanceConfig autoConfig = viewConfig.getAutoInstance(); |
| |
| try { |
| if (checkAutoInstanceConfig(autoConfig, stackId, event.getServiceName(), serviceNames)) { |
| |
| LOG.info("Auto creating instance of view " + viewName + " for cluster " + clusterName + "."); |
| ViewInstanceEntity viewInstanceEntity = createViewInstanceEntity(viewEntity, viewConfig, autoConfig); |
| viewInstanceEntity.setClusterHandle(clusterId); |
| installViewInstance(viewInstanceEntity); |
| } |
| } catch (Exception e) { |
| LOG.error("Can't auto create instance of view " + viewName + " for cluster " + clusterName + |
| ". Caught exception :" + e.getMessage(), e); |
| } |
| } |
| } catch (AmbariException e) { |
| LOG.warn("Unknown cluster id " + clusterId + "."); |
| } |
| } |
| |
| |
| // ----- helper methods ---------------------------------------------------- |
| |
| /** |
| * Determine whether a new view instance should be automatically created and associated with |
| * a cluster based on the given configuration and cluster state. |
| * |
| * @param autoConfig the view instance auto creation configuration |
| * @param stackId the stack id of the cluster |
| * @param serviceName the name of the service added which triggered this check |
| * @param serviceNames the set of service names of the cluster |
| * |
| * @return true if a new view instance should be created |
| */ |
| private boolean checkAutoInstanceConfig(AutoInstanceConfig autoConfig, StackId stackId, |
| String serviceName, Set<String> serviceNames) { |
| |
| if (autoConfig != null) { |
| List<String> autoCreateServices = autoConfig.getServices(); |
| |
| if (autoCreateServices != null && autoCreateServices.contains(serviceName) && |
| serviceNames.containsAll(autoCreateServices)) { |
| |
| String configStackId = autoConfig.getStackId(); |
| |
| if (configStackId != null) { |
| StackId id = new StackId(configStackId); |
| |
| if (id.getStackName().equals(stackId.getStackName())) { |
| |
| String stackVersion = stackId.getStackVersion(); |
| String configStackVersion = id.getStackVersion(); |
| |
| // make sure that the configured stack version equals the cluster stack version (account for *) |
| int compVal = 0; |
| |
| int index = configStackVersion.indexOf('*'); |
| if (index == -1) { |
| compVal = VersionUtils.compareVersions(configStackVersion, stackVersion); |
| } else if (index > 0) { |
| String[] parts = configStackVersion.substring(0, index).split("\\."); |
| compVal = VersionUtils.compareVersions(configStackVersion, stackVersion, parts.length); |
| } |
| |
| return compVal == 0; |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Clear the registry. |
| */ |
| protected void clear() { |
| viewDefinitions.clear(); |
| viewInstanceDefinitions.clear(); |
| subResourceDefinitionsMap.clear(); |
| listeners.clear(); |
| } |
| |
| /** |
| * Get the view resource provider mapping. |
| * |
| * @return the map of view resource providers |
| */ |
| protected Map<Resource.Type, ResourceProvider> getResourceProviders() { |
| return resourceProviders; |
| } |
| |
| // get a view entity for the given internal view name |
| private ViewEntity getDefinition(String viewName) { |
| return viewDefinitions.get(viewName); |
| } |
| |
| // setup the given view definition |
| protected ViewEntity setupViewDefinition(ViewEntity viewDefinition, ClassLoader cl) |
| throws ClassNotFoundException, IntrospectionException { |
| |
| ViewConfig viewConfig = viewDefinition.getConfiguration(); |
| |
| viewDefinition.setClassLoader(cl); |
| |
| List<ParameterConfig> parameterConfigurations = viewConfig.getParameters(); |
| |
| Collection<ViewParameterEntity> parameters = new HashSet<ViewParameterEntity>(); |
| |
| String viewName = viewDefinition.getName(); |
| |
| for (ParameterConfig parameterConfiguration : parameterConfigurations) { |
| ViewParameterEntity viewParameterEntity = new ViewParameterEntity(); |
| |
| viewParameterEntity.setViewName(viewName); |
| viewParameterEntity.setName(parameterConfiguration.getName()); |
| viewParameterEntity.setDescription(parameterConfiguration.getDescription()); |
| viewParameterEntity.setLabel(parameterConfiguration.getLabel()); |
| viewParameterEntity.setPlaceholder(parameterConfiguration.getPlaceholder()); |
| viewParameterEntity.setDefaultValue(parameterConfiguration.getDefaultValue()); |
| viewParameterEntity.setClusterConfig(parameterConfiguration.getClusterConfig()); |
| viewParameterEntity.setRequired(parameterConfiguration.isRequired()); |
| viewParameterEntity.setMasked(parameterConfiguration.isMasked()); |
| viewParameterEntity.setViewEntity(viewDefinition); |
| parameters.add(viewParameterEntity); |
| } |
| viewDefinition.setParameters(parameters); |
| |
| List<ResourceConfig> resourceConfigurations = viewConfig.getResources(); |
| |
| Resource.Type externalResourceType = viewDefinition.getExternalResourceType(); |
| |
| ViewExternalSubResourceProvider viewExternalSubResourceProvider = |
| new ViewExternalSubResourceProvider(externalResourceType, viewDefinition); |
| viewDefinition.addResourceProvider(externalResourceType, viewExternalSubResourceProvider); |
| |
| resourceProviders.put(externalResourceType, viewExternalSubResourceProvider); |
| |
| ResourceInstanceFactoryImpl.addResourceDefinition(externalResourceType, |
| new ViewExternalSubResourceDefinition(externalResourceType)); |
| |
| Collection<ViewResourceEntity> resources = new HashSet<ViewResourceEntity>(); |
| for (ResourceConfig resourceConfiguration : resourceConfigurations) { |
| ViewResourceEntity viewResourceEntity = new ViewResourceEntity(); |
| |
| viewResourceEntity.setViewName(viewName); |
| viewResourceEntity.setName(resourceConfiguration.getName()); |
| viewResourceEntity.setPluralName(resourceConfiguration.getPluralName()); |
| viewResourceEntity.setIdProperty(resourceConfiguration.getIdProperty()); |
| viewResourceEntity.setResource(resourceConfiguration.getResource()); |
| viewResourceEntity.setService(resourceConfiguration.getService()); |
| viewResourceEntity.setProvider(resourceConfiguration.getProvider()); |
| viewResourceEntity.setSubResourceNames(resourceConfiguration.getSubResourceNames()); |
| viewResourceEntity.setViewEntity(viewDefinition); |
| |
| ViewSubResourceDefinition resourceDefinition = new ViewSubResourceDefinition(viewDefinition, resourceConfiguration); |
| viewDefinition.addResourceDefinition(resourceDefinition); |
| |
| Resource.Type type = resourceDefinition.getType(); |
| viewDefinition.addResourceConfiguration(type, resourceConfiguration); |
| |
| if (resourceConfiguration.isExternal()) { |
| viewExternalSubResourceProvider.addResourceName(resourceConfiguration.getName()); |
| } else { |
| ResourceInstanceFactoryImpl.addResourceDefinition(type, resourceDefinition); |
| |
| Class<?> clazz = resourceConfiguration.getResourceClass(cl); |
| String idProperty = resourceConfiguration.getIdProperty(); |
| |
| ViewSubResourceProvider provider = new ViewSubResourceProvider(type, clazz, idProperty, viewDefinition); |
| viewDefinition.addResourceProvider(type, provider); |
| resourceProviders.put(type, provider); |
| |
| resources.add(viewResourceEntity); |
| } |
| viewDefinition.setResources(resources); |
| } |
| |
| ResourceTypeEntity resourceTypeEntity = new ResourceTypeEntity(); |
| resourceTypeEntity.setName(viewName); |
| |
| viewDefinition.setResourceType(resourceTypeEntity); |
| |
| List<PermissionConfig> permissionConfigurations = viewConfig.getPermissions(); |
| |
| Collection<PermissionEntity> permissions = new HashSet<PermissionEntity>(); |
| for (PermissionConfig permissionConfiguration : permissionConfigurations) { |
| PermissionEntity permissionEntity = new PermissionEntity(); |
| |
| permissionEntity.setPermissionName(permissionConfiguration.getName()); |
| permissionEntity.setResourceType(resourceTypeEntity); |
| permissions.add(permissionEntity); |
| } |
| viewDefinition.setPermissions(permissions); |
| |
| View view = null; |
| if (viewConfig.getView() != null) { |
| view = getView(viewConfig.getViewClass(cl), new ViewContextImpl(viewDefinition, this)); |
| } |
| viewDefinition.setView(view); |
| Validator validator = null; |
| if (viewConfig.getValidator() != null) { |
| validator = getValidator(viewConfig.getValidatorClass(cl), new ViewContextImpl(viewDefinition, this)); |
| } |
| viewDefinition.setValidator(validator); |
| viewDefinition.setMask(viewConfig.getMasker()); |
| |
| Set<SubResourceDefinition> subResourceDefinitions = new HashSet<SubResourceDefinition>(); |
| for (Resource.Type type : viewDefinition.getViewResourceTypes()) { |
| subResourceDefinitions.add(new SubResourceDefinition(type)); |
| } |
| subResourceDefinitionsMap.put(viewName, subResourceDefinitions); |
| |
| return viewDefinition; |
| } |
| |
| // create a new view instance definition |
| protected ViewInstanceEntity createViewInstanceDefinition(ViewConfig viewConfig, ViewEntity viewDefinition, |
| InstanceConfig instanceConfig) |
| throws ValidationException, ClassNotFoundException, SystemException { |
| ViewInstanceEntity viewInstanceDefinition = createViewInstanceEntity(viewDefinition, viewConfig, instanceConfig); |
| viewInstanceDefinition.validate(viewDefinition, Validator.ValidationContext.PRE_CREATE); |
| |
| bindViewInstance(viewDefinition, viewInstanceDefinition); |
| return viewInstanceDefinition; |
| } |
| |
| // create a view instance from the given configuration |
| private ViewInstanceEntity createViewInstanceEntity(ViewEntity viewDefinition, ViewConfig viewConfig, |
| InstanceConfig instanceConfig) |
| throws SystemException { |
| ViewInstanceEntity viewInstanceDefinition = |
| new ViewInstanceEntity(viewDefinition, instanceConfig); |
| |
| Map<String, String> properties = new HashMap<String, String>(); |
| |
| for (PropertyConfig propertyConfig : instanceConfig.getProperties()) { |
| properties.put(propertyConfig.getKey(), propertyConfig.getValue()); |
| } |
| setViewInstanceProperties(viewInstanceDefinition, properties, viewConfig, viewDefinition.getClassLoader()); |
| |
| setPersistenceEntities(viewInstanceDefinition); |
| |
| return viewInstanceDefinition; |
| } |
| |
| // bind a view instance definition to the given view definition |
| protected void bindViewInstance(ViewEntity viewDefinition, |
| ViewInstanceEntity viewInstanceDefinition) |
| throws ClassNotFoundException { |
| viewInstanceDefinition.setViewEntity(viewDefinition); |
| |
| ViewContext viewInstanceContext = new ViewContextImpl(viewInstanceDefinition, this); |
| |
| ViewExternalSubResourceService externalSubResourceService = |
| new ViewExternalSubResourceService(viewDefinition.getExternalResourceType(), viewInstanceDefinition); |
| |
| viewInstanceDefinition.addService(ResourceConfig.EXTERNAL_RESOURCE_PLURAL_NAME, externalSubResourceService); |
| |
| Collection<ViewSubResourceDefinition> resourceDefinitions = viewDefinition.getResourceDefinitions().values(); |
| for (ViewSubResourceDefinition resourceDefinition : resourceDefinitions) { |
| |
| Resource.Type type = resourceDefinition.getType(); |
| ResourceConfig resourceConfig = resourceDefinition.getResourceConfiguration(); |
| |
| ViewResourceHandler viewResourceService = new ViewSubResourceService(type, viewInstanceDefinition); |
| |
| ClassLoader cl = viewDefinition.getClassLoader(); |
| |
| Object service = getService(resourceConfig.getServiceClass(cl), viewResourceService, viewInstanceContext); |
| |
| if (resourceConfig.isExternal()) { |
| externalSubResourceService.addResourceService(resourceConfig.getName(), service); |
| } else { |
| viewInstanceDefinition.addService(viewDefinition.getResourceDefinition(type).getPluralName(),service); |
| viewInstanceDefinition.addResourceProvider(type, |
| getProvider(resourceConfig.getProviderClass(cl), viewInstanceContext)); |
| } |
| } |
| viewDefinition.addInstanceDefinition(viewInstanceDefinition); |
| } |
| |
| // Set the entities defined in the view persistence element for the given view instance |
| private static void setPersistenceEntities(ViewInstanceEntity viewInstanceDefinition) { |
| ViewEntity viewDefinition = viewInstanceDefinition.getViewEntity(); |
| ViewConfig viewConfig = viewDefinition.getConfiguration(); |
| |
| Collection<ViewEntityEntity> entities = new HashSet<ViewEntityEntity>(); |
| |
| if (viewConfig != null) { |
| PersistenceConfig persistenceConfig = viewConfig.getPersistence(); |
| |
| if (persistenceConfig != null) { |
| for (EntityConfig entityConfiguration : persistenceConfig.getEntities()) { |
| ViewEntityEntity viewEntityEntity = new ViewEntityEntity(); |
| |
| viewEntityEntity.setViewName(viewDefinition.getName()); |
| viewEntityEntity.setViewInstanceName(viewInstanceDefinition.getName()); |
| viewEntityEntity.setClassName(entityConfiguration.getClassName()); |
| viewEntityEntity.setIdProperty(entityConfiguration.getIdProperty()); |
| viewEntityEntity.setViewInstance(viewInstanceDefinition); |
| |
| entities.add(viewEntityEntity); |
| } |
| } |
| } |
| viewInstanceDefinition.setEntities(entities); |
| } |
| |
| // get the given service class from the given class loader; inject a handler and context |
| private static <T> T getService(Class<T> clazz, |
| final ViewResourceHandler viewResourceHandler, |
| final ViewContext viewInstanceContext) { |
| Injector viewInstanceInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| bind(ViewResourceHandler.class) |
| .toInstance(viewResourceHandler); |
| bind(ViewContext.class) |
| .toInstance(viewInstanceContext); |
| } |
| }); |
| return viewInstanceInjector.getInstance(clazz); |
| } |
| |
| // get the given resource provider class from the given class loader; inject a context |
| private static org.apache.ambari.view.ResourceProvider getProvider( |
| Class<? extends org.apache.ambari.view.ResourceProvider> clazz, |
| final ViewContext viewInstanceContext) { |
| Injector viewInstanceInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| bind(ViewContext.class) |
| .toInstance(viewInstanceContext); |
| } |
| }); |
| return viewInstanceInjector.getInstance(clazz); |
| } |
| |
| // get the given view class from the given class loader; inject a context |
| private static View getView(Class<? extends View> clazz, |
| final ViewContext viewContext) { |
| Injector viewInstanceInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| bind(ViewContext.class) |
| .toInstance(viewContext); |
| } |
| }); |
| return viewInstanceInjector.getInstance(clazz); |
| } |
| |
| // get the given view validator class from the given class loader; inject a context |
| private static Validator getValidator(Class<? extends Validator> clazz, |
| final ViewContext viewContext) { |
| Injector viewInstanceInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| bind(ViewContext.class) |
| .toInstance(viewContext); |
| } |
| }); |
| return viewInstanceInjector.getInstance(clazz); |
| } |
| |
| // create masker from given class; probably replace with injector later |
| private static Masker getMasker(Class<? extends Masker> clazz) { |
| try { |
| return clazz.newInstance(); |
| } catch (Exception e) { |
| LOG.error("Could not create masker instance", e); |
| } |
| return null; |
| } |
| |
| // remove undeployed views from the ambari db |
| private void removeUndeployedViews() { |
| for (ViewEntity viewEntity : viewDAO.findAll()) { |
| String name = viewEntity.getName(); |
| if (!ViewRegistry.getInstance().viewDefinitions.containsKey(name)) { |
| try { |
| viewDAO.remove(viewEntity); |
| } catch (Exception e) { |
| LOG.error("Caught exception undeploying view " + viewEntity.getName(), e); |
| } |
| } |
| } |
| } |
| |
| /** |
| * 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 if the view can not be synced |
| */ |
| private void syncView(ViewEntity view, |
| Set<ViewInstanceEntity> instanceDefinitions) |
| throws Exception { |
| |
| String viewName = view.getName(); |
| ViewEntity persistedView = viewDAO.findByName(viewName); |
| |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("Syncing view " + viewName + "."); |
| } |
| |
| // if the view is not yet persisted ... |
| if (persistedView == null) { |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("Creating view " + viewName + "."); |
| } |
| |
| // create an admin resource type to represent this view |
| ResourceTypeEntity resourceType = resourceTypeDAO.merge(view.getResourceType()); |
| |
| for( ViewInstanceEntity instance : view.getInstances()) { |
| instance.setResource(createViewInstanceResource(resourceType)); |
| } |
| // ... merge the view |
| view.setResourceType(resourceType); |
| persistedView = viewDAO.merge(view); |
| } |
| |
| view.setResourceType(persistedView.getResourceType()); |
| view.setPermissions(persistedView.getPermissions()); |
| |
| // make sure that each instance of the view in the db is reflected in the given view |
| for (ViewInstanceEntity persistedInstance : persistedView.getInstances()){ |
| |
| String instanceName = persistedInstance.getName(); |
| ViewInstanceEntity instance = view.getInstanceDefinition(instanceName); |
| |
| // if the persisted instance is not in the view ... |
| if (instance == null) { |
| if (persistedInstance.isXmlDriven()) { |
| // this instance was persisted from an earlier view.xml but has been removed... |
| // remove it from the db |
| instanceDAO.remove(persistedInstance); |
| } else { |
| // this instance was not specified in the view.xml but was added through the API... |
| // bind it to the view and add it to the registry |
| instanceDAO.merge(persistedInstance); |
| bindViewInstance(view, persistedInstance); |
| instanceDefinitions.add(persistedInstance); |
| } |
| } else { |
| syncViewInstance(instance, persistedInstance); |
| } |
| } |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("Syncing view " + viewName + " complete."); |
| } |
| } |
| |
| // sync the given view instance entity to the matching view instance entity in the registry |
| private void syncViewInstance(ViewInstanceEntity instanceEntity) { |
| String viewName = instanceEntity.getViewDefinition().getViewName(); |
| String version = instanceEntity.getViewDefinition().getVersion(); |
| String instanceName = instanceEntity.getInstanceName(); |
| |
| ViewInstanceEntity registryEntry = getInstanceDefinition(viewName, version, instanceName); |
| if (registryEntry != null) { |
| syncViewInstance(registryEntry, instanceEntity); |
| } |
| } |
| |
| // sync a given view instance entity with another given view instance entity |
| private void syncViewInstance(ViewInstanceEntity instance1, ViewInstanceEntity instance2) { |
| instance1.setLabel(instance2.getLabel()); |
| instance1.setDescription(instance2.getDescription()); |
| instance1.setViewUrl(instance2.getViewUrl()); |
| instance1.setVisible(instance2.isVisible()); |
| instance1.setResource(instance2.getResource()); |
| instance1.setViewInstanceId(instance2.getViewInstanceId()); |
| instance1.setClusterHandle(instance2.getClusterHandle()); |
| instance1.setClusterType(instance2.getClusterType()); |
| instance1.setData(instance2.getData()); |
| instance1.setEntities(instance2.getEntities()); |
| instance1.setProperties(instance2.getProperties()); |
| } |
| |
| // create an admin resource for the given view instance entity and merge it |
| @Transactional |
| ViewInstanceEntity mergeViewInstance(ViewInstanceEntity instanceEntity, ResourceTypeEntity resourceTypeEntity) { |
| // create an admin resource to represent this view instance |
| instanceEntity.setResource(createViewInstanceResource(resourceTypeEntity)); |
| |
| return instanceDAO.merge(instanceEntity); |
| } |
| |
| // create an admin resource to represent a view instance |
| private ResourceEntity createViewInstanceResource(ResourceTypeEntity resourceTypeEntity) { |
| ResourceEntity resourceEntity = new ResourceEntity(); |
| resourceEntity.setResourceType(resourceTypeEntity); |
| resourceDAO.create(resourceEntity); |
| return resourceEntity; |
| } |
| |
| // notify the view identified by the given view name of the given event |
| private void fireEvent(Event event, String viewName) { |
| Set<Listener> listeners = this.listeners.get(viewName); |
| |
| if (listeners != null) { |
| for (Listener listener : listeners) { |
| listener.notify(event); |
| } |
| } |
| } |
| |
| // check that the current user is authorized to access the given view instance resource |
| private boolean checkAuthorization(ResourceEntity resourceEntity) { |
| Long resourceId = (resourceEntity == null) ? null : resourceEntity.getId(); |
| |
| return (resourceId == null) |
| ? AuthorizationHelper.isAuthorized(ResourceType.AMBARI, null, RoleAuthorization.AMBARI_MANAGE_VIEWS) |
| : AuthorizationHelper.isAuthorized(ResourceType.VIEW, resourceId, RoleAuthorization.VIEW_USE); |
| } |
| |
| // fire the onDeploy event. |
| protected void onDeploy(ViewEntity definition) { |
| View view = definition.getView(); |
| if (view != null) { |
| view.onDeploy(definition); |
| } |
| } |
| |
| // remove a privilege entity. |
| private void removePrivilegeEntity(PrivilegeEntity privilegeEntity) { |
| |
| PrincipalEntity principalEntity = privilegeEntity.getPrincipal(); |
| if (principalEntity != null) { |
| principalEntity.removePrivilege(privilegeEntity); |
| } |
| |
| privilegeDAO.remove(privilegeEntity); |
| } |
| |
| |
| /** |
| * Extract a view archive at the specified path |
| * @param path |
| */ |
| public void readViewArchive(Path path) { |
| |
| File viewDir = configuration.getViewsDir(); |
| String extractedArchivesPath = viewDir.getAbsolutePath() + |
| File.separator + EXTRACTED_ARCHIVES_DIR; |
| |
| File archiveFile = path.toAbsolutePath().toFile(); |
| if (extractor.ensureExtractedArchiveDirectory(extractedArchivesPath)) { |
| try { |
| final ViewConfig viewConfig = archiveUtility.getViewConfigFromArchive(archiveFile); |
| String viewName = ViewEntity.getViewName(viewConfig.getName(), viewConfig.getVersion()); |
| final String extractedArchiveDirPath = extractedArchivesPath + File.separator + viewName; |
| final File extractedArchiveDirFile = archiveUtility.getFile(extractedArchiveDirPath); |
| final ViewEntity viewDefinition = new ViewEntity(viewConfig, configuration, extractedArchiveDirPath); |
| addDefinition(viewDefinition); |
| readViewArchive(viewDefinition, archiveFile, extractedArchiveDirFile, ambariMetaInfoProvider.get().getServerVersion()); |
| } catch (Exception e){ |
| LOG.error("Could not process archive at path "+path, e); |
| } |
| } |
| |
| } |
| |
| |
| |
| |
| // read the view archives. |
| private void readViewArchives(boolean systemOnly, boolean useExecutor, |
| String viewNameRegExp) { |
| try { |
| |
| File viewDir = configuration.getViewsDir(); |
| String extractedArchivesPath = viewDir.getAbsolutePath() + |
| File.separator + EXTRACTED_ARCHIVES_DIR; |
| |
| if (extractor.ensureExtractedArchiveDirectory(extractedArchivesPath)) { |
| |
| File[] files = viewDir.listFiles(); |
| |
| if (files != null) { |
| |
| Set<Runnable> extractionRunnables = new HashSet<Runnable>(); |
| |
| final String serverVersion = ambariMetaInfoProvider.get().getServerVersion(); |
| |
| for (final File archiveFile : files) { |
| if (!archiveFile.isDirectory()) { |
| |
| try { |
| final ViewConfig viewConfig = archiveUtility.getViewConfigFromArchive(archiveFile); |
| |
| String commonName = viewConfig.getName(); |
| String version = viewConfig.getVersion(); |
| String viewName = ViewEntity.getViewName(commonName, version); |
| |
| if (!viewName.matches(viewNameRegExp)) { |
| continue; |
| } |
| |
| final String extractedArchiveDirPath = extractedArchivesPath + File.separator + viewName; |
| final File extractedArchiveDirFile = archiveUtility.getFile(extractedArchiveDirPath); |
| |
| final ViewEntity viewDefinition = new ViewEntity(viewConfig, configuration, extractedArchiveDirPath); |
| |
| boolean systemView = viewDefinition.isSystem(); |
| |
| if (!systemOnly || systemView) { |
| // update the registry with the view |
| addDefinition(viewDefinition); |
| |
| // always load system views up front |
| if (systemView || !useExecutor || extractedArchiveDirFile.exists()) { |
| // if the archive is already extracted then load the view now |
| readViewArchive(viewDefinition, archiveFile, extractedArchiveDirFile, serverVersion); |
| } else { |
| // if the archive needs to be extracted then create a runnable to do it |
| extractionRunnables.add(new Runnable() { |
| @Override |
| public void run() { |
| readViewArchive(viewDefinition, archiveFile, extractedArchiveDirFile, serverVersion); |
| migrateDataFromPreviousVersion(viewDefinition, serverVersion); |
| } |
| }); |
| } |
| } |
| } catch (Exception e) { |
| String msg = "Caught exception reading view archive " + archiveFile.getAbsolutePath(); |
| LOG.error(msg, e); |
| } |
| } |
| } |
| |
| for(ViewEntity view : getDefinitions()) { |
| if (view.getStatus() == ViewDefinition.ViewStatus.DEPLOYED) { |
| // migrate views that are not need extraction, for ones that need call will be done in the runnable. |
| migrateDataFromPreviousVersion(view, serverVersion); |
| } |
| } |
| |
| if (useExecutor && extractionRunnables.size() > 0) { |
| final ExecutorService executorService = getExecutorService(configuration); |
| |
| for (Runnable runnable : extractionRunnables) { |
| // submit a new task for each archive that needs extraction |
| executorService.submit(runnable); |
| } |
| } |
| |
| if (configuration.isViewRemoveUndeployedEnabled()) { |
| removeUndeployedViews(); |
| } |
| } |
| } else { |
| LOG.error("Could not create extracted view archive directory " + extractedArchivesPath + "."); |
| } |
| } catch (Exception e) { |
| LOG.error("Caught exception reading view archives.", e); |
| } |
| } |
| |
| // read a view archive |
| private void readViewArchive(ViewEntity viewDefinition, |
| File archiveFile, |
| File extractedArchiveDirFile, |
| String serverVersion) { |
| |
| setViewStatus(viewDefinition, ViewEntity.ViewStatus.DEPLOYING, "Deploying " + extractedArchiveDirFile + "."); |
| |
| String extractedArchiveDirPath = extractedArchiveDirFile.getAbsolutePath(); |
| |
| LOG.info("Reading view archive " + archiveFile + "."); |
| |
| try { |
| // extract the archive and get the class loader |
| ClassLoader cl = extractor.extractViewArchive(viewDefinition, archiveFile, extractedArchiveDirFile); |
| |
| configureViewLogging(viewDefinition, cl); |
| |
| ViewConfig viewConfig = archiveUtility.getViewConfigFromExtractedArchive(extractedArchiveDirPath, |
| configuration.isViewValidationEnabled()); |
| |
| viewDefinition.setConfiguration(viewConfig); |
| |
| if (checkViewVersions(viewDefinition, serverVersion)) { |
| setupViewDefinition(viewDefinition, cl); |
| |
| Set<ViewInstanceEntity> instanceDefinitions = new HashSet<ViewInstanceEntity>(); |
| |
| for (InstanceConfig instanceConfig : viewConfig.getInstances()) { |
| ViewInstanceEntity instanceEntity = createViewInstanceDefinition(viewConfig, viewDefinition, instanceConfig); |
| instanceEntity.setXmlDriven(true); |
| instanceDefinitions.add(instanceEntity); |
| } |
| persistView(viewDefinition, instanceDefinitions); |
| |
| // auto instances of loaded old views for doing data migration can not be installed |
| if (getDefinition(viewDefinition.getViewName(), viewDefinition.getVersion()) != null) { |
| // add auto instance configurations if required |
| addAutoInstanceDefinition(viewDefinition); |
| } |
| |
| setViewStatus(viewDefinition, ViewEntity.ViewStatus.DEPLOYED, "Deployed " + extractedArchiveDirPath + "."); |
| |
| LOG.info("View deployed: " + viewDefinition.getName() + "."); |
| } |
| } catch (Exception e) { |
| String msg = "Caught exception loading view " + viewDefinition.getName(); |
| |
| setViewStatus(viewDefinition, ViewEntity.ViewStatus.ERROR, msg + " : " + e.getMessage()); |
| LOG.error(msg, e); |
| } |
| } |
| |
| private void migrateDataFromPreviousVersion(ViewEntity viewDefinition, String serverVersion) { |
| if (!viewDefinitions.containsKey(viewDefinition.getName())) { // migrate only registered views to avoid recursive calls |
| LOG.debug("Cancel auto migration of not loaded view: " + viewDefinition.getName() + "."); |
| return; |
| } |
| try { |
| |
| for (ViewInstanceEntity instance : viewDefinition.getInstances()) { |
| LOG.debug("Try to migrate the data from previous version of: " + viewDefinition.getName() + "/" + |
| instance.getInstanceName() + "."); |
| ViewInstanceEntity latestUnregisteredView = getLatestUnregisteredInstance(serverVersion, instance); |
| |
| if (latestUnregisteredView != null) { |
| String instanceName = instance.getViewEntity().getName() + "/" + instance.getName(); |
| try { |
| LOG.info("Found previous version of the view instance " + instanceName + ": " + |
| latestUnregisteredView.getViewEntity().getName() + "/" + latestUnregisteredView.getName()); |
| getViewDataMigrationUtility().migrateData(instance, latestUnregisteredView, true); |
| LOG.info("View data migrated: " + viewDefinition.getName() + "."); |
| } catch (ViewDataMigrationException e) { |
| LOG.error("Error occurred during migration", e); |
| } |
| } |
| } |
| |
| } catch (Exception e) { |
| String msg = "Caught exception migrating data in view " + viewDefinition.getName(); |
| |
| setViewStatus(viewDefinition, ViewEntity.ViewStatus.ERROR, msg + " : " + e.getMessage()); |
| LOG.error(msg, e); |
| } |
| } |
| |
| /** |
| * copies non-log4j properties (like ambari.log.dir) from ambari's log4j.properties into view's log4j properties |
| * and removes log4j specific properties (log4j.rootLogger) inside ambari's log4j.properties from view's log4j properties |
| * It then configures the log4j with view's properties. |
| * |
| * @param viewDefinition |
| * @param cl |
| */ |
| private void configureViewLogging(ViewEntity viewDefinition, ClassLoader cl) { |
| InputStream viewLog4jStream = cl.getResourceAsStream(VIEW_LOG_FILE); |
| InputStream ambariLog4jStream = null; |
| if (null != viewLog4jStream) { |
| try { |
| Properties viewLog4jConfig = new Properties(); |
| viewLog4jConfig.load(viewLog4jStream); |
| LOG.info("setting up logging for view {} as per property file {}", viewDefinition.getName(), VIEW_LOG_FILE); |
| |
| ambariLog4jStream = cl.getResourceAsStream(AMBARI_LOG_FILE); |
| if (null != ambariLog4jStream) { |
| Properties ambariLog4jConfig = new Properties(); |
| ambariLog4jConfig.load(ambariLog4jStream); |
| |
| // iterate through all the ambari configs and get the once not starting from log4j |
| // set them into view properties and remove any log4j property which view might be overriding. |
| for (Object property : ambariLog4jConfig.keySet()) { |
| String prop = (String) property; |
| if (prop.startsWith(LOG4J)) { |
| viewLog4jConfig.remove(prop); |
| } else { |
| viewLog4jConfig.put(prop, ambariLog4jConfig.getProperty(prop)); |
| } |
| } |
| } |
| |
| PropertyConfigurator.configure(viewLog4jConfig); |
| } catch (IOException e) { |
| LOG.error("Error occurred while configuring logs for {}", viewDefinition.getName()); |
| } finally { |
| if (ambariLog4jStream != null) { |
| try { |
| ambariLog4jStream.close(); |
| } catch (IOException e) { |
| } |
| } |
| |
| if (viewLog4jStream != null) { |
| try { |
| viewLog4jStream.close(); |
| } catch (IOException e) { |
| } |
| } |
| } |
| } |
| } |
| |
| private void addAutoInstanceDefinition(ViewEntity viewEntity) { |
| ViewConfig viewConfig = viewEntity.getConfiguration(); |
| String viewName = viewEntity.getViewName(); |
| |
| AutoInstanceConfig autoInstanceConfig = viewConfig.getAutoInstance(); |
| if (autoInstanceConfig == null) { |
| return; |
| } |
| |
| List<String> services = autoInstanceConfig.getServices(); |
| List<String> permissions = autoInstanceConfig.getPermissions(); |
| |
| Map<String, org.apache.ambari.server.state.Cluster> allClusters = clustersProvider.get().getClusters(); |
| for (org.apache.ambari.server.state.Cluster cluster : allClusters.values()) { |
| |
| String clusterName = cluster.getClusterName(); |
| Long clusterId= cluster.getClusterId(); |
| StackId stackId = cluster.getCurrentStackVersion(); |
| Set<String> serviceNames = cluster.getServices().keySet(); |
| |
| for (String service : services) { |
| try { |
| |
| if (checkAutoInstanceConfig(autoInstanceConfig, stackId, service, serviceNames)) { |
| LOG.info("Auto creating instance of view " + viewName + " for cluster " + clusterName + "."); |
| ViewInstanceEntity viewInstanceEntity = createViewInstanceEntity(viewEntity, viewConfig, autoInstanceConfig); |
| viewInstanceEntity.setClusterHandle(clusterId); |
| installViewInstance(viewInstanceEntity); |
| addClusterInheritedPermissions(viewInstanceEntity, permissions); |
| } |
| } catch (Exception e) { |
| LOG.error("Can't auto create instance of view " + viewName + " for cluster " + clusterName + |
| ". Caught exception :" + e.getMessage(), e); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Validates principalTypes and creates privilege entities for each permission type for the view instance entity |
| * resource. |
| * @param viewInstanceEntity - view instance entity for which permission has to be set. |
| * @param principalTypes - list of cluster inherited principal types |
| */ |
| @Transactional |
| private void addClusterInheritedPermissions(ViewInstanceEntity viewInstanceEntity, List<String> principalTypes) { |
| List<String> validPermissions = FluentIterable.from(principalTypes) |
| .filter(ClusterInheritedPermissionHelper.validPrincipalTypePredicate) |
| .toList(); |
| |
| for(String permission: validPermissions) { |
| addClusterInheritedPermission(viewInstanceEntity, permission); |
| } |
| } |
| |
| private void addClusterInheritedPermission(ViewInstanceEntity viewInstanceEntity, String principalType) { |
| ResourceEntity resource = viewInstanceEntity.getResource(); |
| List<PrincipalEntity> principals = principalDAO.findByPrincipalType(principalType); |
| if (principals.size() == 0) { |
| LOG.error("Failed to find principal for principal type '{}'", principalType); |
| return; |
| } |
| |
| PrincipalEntity principal = principals.get(0); // There will be only one principal associated with the principal type |
| PermissionEntity permission = permissionDAO.findViewUsePermission(); |
| |
| if (!privilegeDAO.exists(principal, resource, permission)) { |
| PrivilegeEntity privilege = new PrivilegeEntity(); |
| privilege.setPrincipal(principal); |
| privilege.setResource(resource); |
| privilege.setPermission(permission); |
| |
| privilegeDAO.create(privilege); |
| } |
| } |
| |
| /** |
| * Check the configured view max and min Ambari versions for the given view entity |
| * against the given Ambari server version. |
| * |
| * @param view the view |
| * @param serverVersion the server version |
| * |
| * @return true if the given server version >= min version && <= max version for the given view |
| */ |
| protected boolean checkViewVersions(ViewEntity view, String serverVersion) { |
| ViewConfig config = view.getConfiguration(); |
| |
| return checkViewVersion(view, config.getMinAmbariVersion(), serverVersion, "minimum", -1, "less than") && |
| checkViewVersion(view, config.getMaxAmbariVersion(), serverVersion, "maximum", 1, "greater than"); |
| |
| } |
| |
| // check the given version against the actual Ambari server version |
| private boolean checkViewVersion(ViewEntity view, String version, String serverVersion, String label, |
| int errValue, String errMsg) { |
| |
| if (version != null && !version.isEmpty()) { |
| |
| // make sure that the given version is a valid version string |
| if (!version.matches(VIEW_AMBARI_VERSION_REGEXP)) { |
| String msg = "The configured " + label + " Ambari version " + version + " for view " + |
| view.getName() + " is not valid."; |
| |
| setViewStatus(view, ViewEntity.ViewStatus.ERROR, msg); |
| LOG.error(msg); |
| return false; |
| } |
| |
| int index = version.indexOf('*'); |
| |
| int compVal = index == -1 ? VersionUtils.compareVersions(serverVersion, version) : |
| index > 0 ? VersionUtils.compareVersions(serverVersion, version.substring(0, index), index) : 0; |
| |
| if (compVal == errValue) { |
| String msg = "The Ambari server version " + serverVersion + " is " + errMsg + " the configured " + label + |
| " Ambari version " + version + " for view " + view.getName(); |
| |
| setViewStatus(view, ViewEntity.ViewStatus.ERROR, msg); |
| LOG.error(msg); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| // persist the given view and its instances |
| @Transactional |
| void persistView(ViewEntity viewDefinition, Set<ViewInstanceEntity> instanceDefinitions) throws Exception { |
| // ensure that the view entity matches the db |
| syncView(viewDefinition, instanceDefinitions); |
| |
| onDeploy(viewDefinition); |
| |
| // update the registry with the view instances |
| for (ViewInstanceEntity instanceEntity : instanceDefinitions) { |
| addInstanceDefinition(viewDefinition, instanceEntity); |
| handlerList.addViewInstance(instanceEntity); |
| } |
| } |
| |
| // extract the view archive for the given path. |
| protected static boolean extractViewArchive(String archivePath, ViewModule viewModule, boolean systemOnly) |
| throws Exception { |
| Injector injector = Guice.createInjector(viewModule); |
| |
| ViewExtractor extractor = injector.getInstance(ViewExtractor.class); |
| ViewArchiveUtility archiveUtility = injector.getInstance(ViewArchiveUtility.class); |
| Configuration configuration = injector.getInstance(Configuration.class); |
| |
| File viewDir = configuration.getViewsDir(); |
| |
| String extractedArchivesPath = viewDir.getAbsolutePath() + |
| File.separator + EXTRACTED_ARCHIVES_DIR; |
| |
| if (extractor.ensureExtractedArchiveDirectory(extractedArchivesPath)) { |
| |
| File archiveFile = archiveUtility.getFile(archivePath); |
| |
| ViewConfig viewConfig = archiveUtility.getViewConfigFromArchive(archiveFile); |
| |
| String commonName = viewConfig.getName(); |
| String version = viewConfig.getVersion(); |
| String viewName = ViewEntity.getViewName(commonName, version); |
| |
| String extractedArchiveDirPath = extractedArchivesPath + File.separator + viewName; |
| File extractedArchiveDirFile = archiveUtility.getFile(extractedArchiveDirPath); |
| |
| if (!extractedArchiveDirFile.exists()) { |
| ViewEntity viewDefinition = new ViewEntity(viewConfig, configuration, extractedArchiveDirPath); |
| |
| if (!systemOnly || viewDefinition.isSystem()) { |
| ClassLoader classLoader = null; |
| try { |
| classLoader = extractor.extractViewArchive(viewDefinition, archiveFile, extractedArchiveDirFile); |
| return true; |
| } finally { |
| if (classLoader != null && classLoader instanceof ViewClassLoader) { |
| try { |
| ((ViewClassLoader)classLoader).close(); |
| } catch (IOException e) { |
| } |
| } |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| // set the status of the given view. |
| private void setViewStatus(ViewEntity viewDefinition, ViewEntity.ViewStatus status, String statusDetail) { |
| viewDefinition.setStatus(status); |
| viewDefinition.setStatusDetail(statusDetail); |
| } |
| |
| // Get the view extraction thread pool |
| private static synchronized ExecutorService getExecutorService(Configuration configuration) { |
| if (executorService == null) { |
| LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(); |
| |
| ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( |
| configuration.getViewExtractionThreadPoolCoreSize(), |
| configuration.getViewExtractionThreadPoolMaxSize(), |
| configuration.getViewExtractionThreadPoolTimeout(), |
| TimeUnit.MILLISECONDS, |
| queue); |
| |
| threadPoolExecutor.allowCoreThreadTimeOut(true); |
| executorService = threadPoolExecutor; |
| } |
| return executorService; |
| } |
| |
| /** |
| * Factory method to create a view URL stream provider. |
| * |
| * @param viewContext the view context |
| * |
| * @return a new view URL stream provider |
| */ |
| protected ViewURLStreamProvider createURLStreamProvider(ViewContext viewContext) { |
| ComponentSSLConfiguration sslConfiguration = ComponentSSLConfiguration.instance(); |
| org.apache.ambari.server.controller.internal.URLStreamProvider streamProvider = |
| new org.apache.ambari.server.controller.internal.URLStreamProvider( |
| configuration.getRequestConnectTimeout(), |
| configuration.getRequestReadTimeout(), |
| sslConfiguration.getTruststorePath(), |
| sslConfiguration.getTruststorePassword(), |
| sslConfiguration.getTruststoreType()); |
| return new ViewURLStreamProvider(viewContext, streamProvider); |
| } |
| |
| /** |
| * Factory method to create a view Ambari stream provider. |
| * |
| * @return a new view Ambari stream provider |
| */ |
| protected ViewAmbariStreamProvider createAmbariStreamProvider() { |
| ComponentSSLConfiguration sslConfiguration = ComponentSSLConfiguration.instance(); |
| org.apache.ambari.server.controller.internal.URLStreamProvider streamProvider = |
| new org.apache.ambari.server.controller.internal.URLStreamProvider( |
| configuration.getViewAmbariRequestConnectTimeout(), |
| configuration.getViewAmbariRequestReadTimeout(), |
| sslConfiguration.getTruststorePath(), |
| sslConfiguration.getTruststorePassword(), |
| sslConfiguration.getTruststoreType()); |
| return new ViewAmbariStreamProvider(streamProvider, ambariSessionManager, AmbariServer.getController()); |
| } |
| |
| /** |
| * Get Remote Ambari Cluster Stream provider |
| * |
| * @param clusterId |
| * @return |
| */ |
| protected AmbariStreamProvider createRemoteAmbariStreamProvider(Long clusterId){ |
| RemoteAmbariClusterEntity clusterEntity = remoteAmbariClusterDAO.findById(clusterId); |
| if(clusterEntity != null) { |
| return new RemoteAmbariStreamProvider(getBaseurl(clusterEntity.getUrl()), |
| clusterEntity.getUsername(),clusterEntity.getPassword(), |
| configuration.getViewAmbariRequestConnectTimeout(),configuration.getViewAmbariRequestReadTimeout()); |
| } |
| return null; |
| } |
| |
| /** |
| * Get baseurl of the cluster |
| * baseurl wil be http://host:port |
| * |
| * @param url will be in format like http://host:port/api/v1/clusters/clusterName |
| * @return baseurl |
| */ |
| private String getBaseurl(String url){ |
| int index = url.indexOf(API_PREFIX); |
| return url.substring(0,index); |
| } |
| |
| /** |
| * From all extracted views in the work directory finds ones that are present only in |
| * extracted version (not registered in the registry during startup). |
| * If jar is not exists, that means that this view is previous version of view. |
| * Finds latest between unregistered instances and returns it. |
| * |
| * @param serverVersion server version |
| * @param instance view instance entity |
| * @return latest unregistered instance of same name of same view. |
| */ |
| private ViewInstanceEntity getLatestUnregisteredInstance(String serverVersion, ViewInstanceEntity instance) |
| throws JAXBException, IOException, SAXException { |
| File viewDir = configuration.getViewsDir(); |
| |
| String extractedArchivesPath = viewDir.getAbsolutePath() + |
| File.separator + EXTRACTED_ARCHIVES_DIR; |
| |
| File extractedArchivesDir = new File(extractedArchivesPath); |
| File[] extractedArchives = extractedArchivesDir.listFiles(); |
| |
| // find all view archives from previous Ambari versions |
| Map<ViewInstanceEntity, Long> unregInstancesTimestamps = new HashMap<>(); |
| if (extractedArchives != null) { |
| |
| for (File archiveDir : extractedArchives) { |
| if (archiveDir.isDirectory()) { |
| ViewConfig uViewConfig = archiveUtility.getViewConfigFromExtractedArchive(archiveDir.getPath(), false); |
| if (!uViewConfig.isSystem()) { |
| // load prev versions of same view |
| if (!uViewConfig.getName().equals(instance.getViewEntity().getViewName())) { |
| continue; |
| } |
| |
| // check if it's not registered yet. It means that jar file is not present while directory in |
| // work dir present, so maybe it's prev version of view. |
| if (viewDefinitions.containsKey(ViewEntity.getViewName(uViewConfig.getName(), uViewConfig.getVersion()))) { |
| continue; |
| } |
| |
| LOG.debug("Unregistered extracted view found: " + archiveDir.getPath()); |
| |
| ViewEntity uViewDefinition = new ViewEntity(uViewConfig, configuration, archiveDir.getPath()); |
| readViewArchive(uViewDefinition, archiveDir, archiveDir, serverVersion); |
| for (ViewInstanceEntity instanceEntity : uViewDefinition.getInstances()) { |
| LOG.debug(uViewDefinition.getName() + " instance found: " + instanceEntity.getInstanceName()); |
| unregInstancesTimestamps.put(instanceEntity, archiveDir.lastModified()); |
| } |
| } |
| } |
| } |
| |
| } |
| |
| // Find latest previous version |
| long latestPrevInstanceTimestamp = 0; |
| ViewInstanceEntity latestPrevInstance = null; |
| for (ViewInstanceEntity unregInstance : unregInstancesTimestamps.keySet()) { |
| if (unregInstance.getName().equals(instance.getName())) { |
| if (unregInstancesTimestamps.get(unregInstance) > latestPrevInstanceTimestamp) { |
| latestPrevInstance = unregInstance; |
| latestPrevInstanceTimestamp = unregInstancesTimestamps.get(latestPrevInstance); |
| } |
| } |
| } |
| if (latestPrevInstance != null) { |
| LOG.debug("Previous version of " + instance.getViewEntity().getName() + "/" + instance.getName() + " found: " + |
| latestPrevInstance.getViewEntity().getName() + "/" + latestPrevInstance.getName()); |
| } else { |
| LOG.debug("Previous version of " + instance.getViewEntity().getName() + "/" + instance.getName() + " not found"); |
| } |
| return latestPrevInstance; |
| } |
| |
| protected ViewDataMigrationUtility getViewDataMigrationUtility() { |
| if (viewDataMigrationUtility == null) { |
| viewDataMigrationUtility = new ViewDataMigrationUtility(this); |
| } |
| return viewDataMigrationUtility; |
| } |
| |
| protected void setViewDataMigrationUtility(ViewDataMigrationUtility viewDataMigrationUtility) { |
| this.viewDataMigrationUtility = viewDataMigrationUtility; |
| } |
| |
| /** |
| * Module for stand alone view registry. |
| */ |
| protected static class ViewModule extends AbstractModule { |
| |
| @Override |
| protected void configure() { |
| Configuration configuration = new Configuration(); |
| bind(Configuration.class).toInstance(configuration); |
| bind(OsFamily.class).toInstance(new OsFamily(configuration)); |
| } |
| } |
| } |