@Override public Object perform(String name, Object obj, ApiRequest request) { if (!(obj instanceof Service)) { return null; } final Service service = (Service) obj; final Map<String, ServiceLink> newServiceLinks = populateNewServiceLinks(request); validateLinks(newServiceLinks); if (newServiceLinks != null) { lockManager.lock( new ServiceDiscoveryServiceSetLinksLock(service), new LockCallbackNoReturn() { @Override public void doWithLockNoResult() { // remove old listeners set removeOldServiceMaps(service, newServiceLinks); // create a new set createNewServiceMaps(service, newServiceLinks); } }); } return service; }
@Override public void remove(final Service service) { // do with lock to prevent intervention to sidekick service activate lockManager.lock( createLock(Arrays.asList(service)), new LockCallbackNoReturn() { @Override public void doWithLockNoResult() { // in remove, we don't care about the sidekicks, and remove only requested service deleteServiceInstances(service); List<? extends ServiceExposeMap> unmanagedMaps = expMapDao.getUnmanagedServiceInstanceMapsToRemove(service.getId()); for (ServiceExposeMap unmanagedMap : unmanagedMaps) { objectProcessMgr.scheduleStandardProcessAsync( StandardProcess.REMOVE, unmanagedMap, null); } sdSvc.removeServiceMaps(service); } protected void deleteServiceInstances(final Service service) { List<DeploymentUnit> units = unitInstanceFactory.collectDeploymentUnits( Arrays.asList(service), new DeploymentServiceContext()); for (DeploymentUnit unit : units) { unit.remove(false, ServiceDiscoveryConstants.AUDIT_LOG_REMOVE_EXTRA); } } }); }
@Override public HandlerResult handle(ProcessState state, ProcessInstance process) { final Instance instance = (Instance) state.getResource(); List<Volume> volumes = InstanceHelpers.extractVolumesFromMounts(instance, objectManager); for (final Volume v : volumes) { String driver = DataAccessor.fieldString(v, VolumeConstants.FIELD_VOLUME_DRIVER); if (StringUtils.isNotEmpty(driver) && !VolumeConstants.LOCAL_DRIVER.equals(driver)) { StoragePool sp = storagePoolDao.findStoragePoolByDriverName(v.getAccountId(), driver); if (sp == null) { continue; } final String accessMode = sp.getVolumeAccessMode(); if (StringUtils.isNotEmpty(accessMode) && StringUtils.isEmpty(v.getAccessMode()) && !accessMode.equals(v.getAccessMode())) { lockManager.lock( new InstanceVolumeAccessModeLock(v.getId()), new LockCallbackNoReturn() { @Override public void doWithLockNoResult() { objectManager.setFields(v, VOLUME.ACCESS_MODE, accessMode); } }); } } } return null; }
@Override public List<? extends ProjectMember> setProjectMembers( final Account project, final Set<Member> members) { return lockManager.lock( new ProjectLock(project), new LockCallback<List<? extends ProjectMember>>() { public List<? extends ProjectMember> doWithLock() { List<? extends ProjectMember> previousMembers = getActiveProjectMembers(project.getId()); Set<Member> otherPreviosMembers = new HashSet<>(); for (ProjectMember member : previousMembers) { String projectId = (String) ApiContext.getContext() .getIdFormatter() .formatId(objectManager.getType(Account.class), member.getProjectId()); otherPreviosMembers.add(new Member(member, projectId)); } Set<Member> create = new HashSet<Member>(members); Set<Member> delete = new HashSet<Member>(otherPreviosMembers); for (Member member : members) { if (delete.remove(member)) { create.remove(member); } } Condition allMembers = DSL.falseCondition(); for (Member member : delete) { allMembers = allMembers.or( PROJECT_MEMBER .EXTERNAL_ID .eq(member.getExternalId()) .and(PROJECT_MEMBER.EXTERNAL_ID_TYPE.eq(member.getExternalIdType())) .and(PROJECT_MEMBER.PROJECT_ID.eq(project.getId())) .and(PROJECT_MEMBER.STATE.eq(CommonStatesConstants.ACTIVE))); } List<? extends ProjectMember> toDelete = create().selectFrom(PROJECT_MEMBER).where(allMembers).fetch(); for (ProjectMember member : toDelete) { objectProcessManager.executeStandardProcess(StandardProcess.DEACTIVATE, member, null); objectProcessManager.executeStandardProcess(StandardProcess.REMOVE, member, null); } List<ProjectMember> newMembers = new ArrayList<>(); for (Member member : create) { newMembers.add(createProjectMember(project, member)); } return getActiveProjectMembers(project.getId()); } }); }
/** * @param service * @param checkState * @return true if this service needs to be reconciled */ protected boolean activate(final Service service, final boolean checkState) { // return immediately if inactive if (service == null || !sdSvc.isActiveService(service)) { return false; } final List<Service> services = new ArrayList<>(); services.add(service); return lockManager.lock( checkState ? null : createLock(services), new LockCallback<Boolean>() { @Override public Boolean doWithLock() { if (!sdSvc.isActiveService(service)) { return false; } // get existing deployment units ServiceDeploymentPlanner planner = getPlanner(services); // don't process if there is no need to reconcile boolean needToReconcile = needToReconcile(services, planner); if (!needToReconcile) { return false; } if (checkState) { return !planner.isHealthcheckInitiailizing(); } activateServices(service, services); activateDeploymentUnits(planner); // reload planner as there can be new hosts added for Global services planner = getPlanner(services); if (needToReconcile(services, planner)) { throw new IllegalStateException( "Failed to do service reconcile for service [" + service.getId() + "]"); } return false; } }); }
@Override public void deactivate(final Service service) { // do with lock to prevent intervention to sidekick service activate lockManager.lock( createLock(Arrays.asList(service)), new LockCallbackNoReturn() { @Override public void doWithLockNoResult() { // in deactivate, we don't care about the sidekicks, and deactivate only requested // service List<DeploymentUnit> units = unitInstanceFactory.collectDeploymentUnits( Arrays.asList(service), new DeploymentServiceContext()); for (DeploymentUnit unit : units) { unit.stop(); } } }); }
@Override public HandlerResult handle(ProcessState state, ProcessInstance process) { final ExternalEvent event = (ExternalEvent) state.getResource(); if (!ExternalEventConstants.KIND_SERVICE_EVENT.equals(event.getKind())) { return null; } lockManager.lock( new ExternalEventLock(SERVICE_LOCK_NAME, event.getAccountId(), event.getExternalId()), new LockCallbackNoReturn() { @Override public void doWithLockNoResult() { Map<String, Object> serviceData = CollectionUtils.toMap(DataUtils.getFields(event).get(FIELD_SERVICE)); if (serviceData.isEmpty()) { log.warn("Empty service for externalServiceEvent: {}.", event); return; } String kind = serviceData.get(ObjectMetaDataManager.KIND_FIELD) != null ? serviceData.get(ObjectMetaDataManager.KIND_FIELD).toString() : null; if (StringUtils.isEmpty(kind) || schemaFactory.getSchema(kind) == null) { log.warn("Couldn't find schema for service type [{}]. Returning.", kind); return; } if (StringUtils.equals(event.getEventType(), TYPE_SERVICE_CREATE)) { createService(event, serviceData); } else if (StringUtils.equals(event.getEventType(), TYPE_SERVICE_UPDATE)) { updateService(event, serviceData); } else if (StringUtils.equals(event.getEventType(), TYPE_SERVICE_DELETE)) { deleteService(event, serviceData); } else if (StringUtils.equals(event.getEventType(), TYPE_STACK_DELETE)) { deleteStack(event, serviceData); } } }); return null; }
@Override public HandlerResult handle(ProcessState state, ProcessInstance process) { Port port = (Port) state.getResource(); final Instance instance = getObjectManager().loadResource(Instance.class, port.getInstanceId()); if (instance == null) { return null; } lockManager.lock( new InstancePortsLock(instance), new LockCallbackNoReturn() { @Override public void doWithLockNoResult() { processPorts(instance); } }); return null; }
protected void restartDeploymentUnits( final Service service, final Map<String, List<Instance>> deploymentUnitsToStop) { // hold the lock so service.reconcile triggered by config.update // (in turn triggered by instance.remove) won't interfere lockManager.lock( new ServicesSidekickLock(Arrays.asList(service)), new LockCallbackNoReturn() { @Override public void doWithLockNoResult() { // 1. Wait for the service instances to become healthy waitForHealthyState(service); // 2. stop instances stopInstances(deploymentUnitsToStop); // 3. wait for reconcile (instances will be restarted along) deploymentMgr.activate(service); } }); }
protected void upgradeDeploymentUnits( final Service service, final Map<String, List<Instance>> deploymentUnitInstancesToUpgrade, final Map<String, List<Instance>> deploymentUnitInstancesUpgradedManaged, final Map<String, List<Instance>> deploymentUnitInstancesUpgradedUnmanaged, final Map<String, List<Instance>> deploymentUnitInstancesToCleanup, final long batchSize, final boolean startFirst, final boolean fullUpgrade, final boolean isUpgrade) { // hold the lock so service.reconcile triggered by config.update // (in turn triggered by instance.remove) won't interfere lockManager.lock( new ServicesSidekickLock(Arrays.asList(service)), new LockCallbackNoReturn() { @Override public void doWithLockNoResult() { // wait for healthy only for upgrade // should be skipped for rollback if (isUpgrade) { waitForHealthyState(service); } // mark for upgrade markForUpgrade(batchSize); if (startFirst) { // 1. reconcile to start new instances deploymentMgr.activate(service); // 2. stop instances stopInstances(deploymentUnitInstancesToCleanup); } else { // reverse order // 1. stop instances stopInstances(deploymentUnitInstancesToCleanup); // 2. wait for reconcile (new instances will be started along) deploymentMgr.activate(service); } if (isUpgrade) { waitForHealthyState(service); } } protected void markForUpgrade(final long batchSize) { markForCleanup(batchSize, fullUpgrade); } protected void markForCleanup(final long batchSize, boolean fullUpgrade) { long i = 0; Iterator<Map.Entry<String, List<Instance>>> it = deploymentUnitInstancesToUpgrade.entrySet().iterator(); while (it.hasNext() && i < batchSize) { Map.Entry<String, List<Instance>> instances = it.next(); String deploymentUnitUUID = instances.getKey(); markForRollback(deploymentUnitUUID); for (Instance instance : instances.getValue()) { ServiceExposeMap map = objectManager.findAny( ServiceExposeMap.class, SERVICE_EXPOSE_MAP.INSTANCE_ID, instance.getId()); setUpgrade(map, true); } deploymentUnitInstancesToCleanup.put(deploymentUnitUUID, instances.getValue()); it.remove(); i++; } } protected void markForRollback(String deploymentUnitUUIDToRollback) { List<Instance> instances = new ArrayList<>(); if (fullUpgrade) { // for full upgrade, we don't care what deployment unit needs to be rolled back String toExtract = null; for (String key : deploymentUnitInstancesUpgradedUnmanaged.keySet()) { if (toExtract != null) { break; } toExtract = key; } instances = deploymentUnitInstancesUpgradedUnmanaged.get(toExtract); deploymentUnitInstancesUpgradedUnmanaged.remove(toExtract); } else { // for partial upgrade, rollback a specific deployment unit instances = deploymentUnitInstancesUpgradedUnmanaged.get(deploymentUnitUUIDToRollback); } if (instances != null) { for (Instance instance : instances) { ServiceExposeMap map = objectManager.findAny( ServiceExposeMap.class, SERVICE_EXPOSE_MAP.INSTANCE_ID, instance.getId()); setUpgrade(map, false); } deploymentUnitInstancesUpgradedManaged.put(deploymentUnitUUIDToRollback, instances); } } }); }