Skip to content
This repository has been archived by the owner on Jul 11, 2022. It is now read-only.

Commit

Permalink
[BZ 1120418] Initial proof-of-concept for job and step builders for s…
Browse files Browse the repository at this point in the history
…torage maintenance workflow.
  • Loading branch information
Stefan Negrea committed Jul 24, 2014
1 parent 23e0ef3 commit 0f1b326
Show file tree
Hide file tree
Showing 7 changed files with 429 additions and 0 deletions.
13 changes: 13 additions & 0 deletions modules/enterprise/server/storage-maintenance/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>rhq-enterprise-server</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
Expand Down Expand Up @@ -100,6 +106,13 @@
<artifactId>hibernate-entitymanager</artifactId>
</dependency>

<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-6.0</artifactId>
<scope>provided</scope>
<type>pom</type>
</dependency>

<!-- Test dependencies -->
<dependency>
<groupId>${project.groupId}</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* RHQ Management Platform
* Copyright (C) 2005-2014 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.server.storage.maintenance;

import java.util.ArrayList;
import java.util.List;

import org.rhq.core.domain.storage.MaintenanceJob;
import org.rhq.core.domain.storage.MaintenanceStep;
import org.rhq.server.storage.maintenance.step.MaintenanceStepFacade;
import org.rhq.server.storage.maintenance.step.ShutdownStorageClient;
import org.rhq.server.storage.maintenance.step.StartStorageClient;
import org.rhq.server.storage.maintenance.step.UpdateStorageNodeEndpoints;
import org.rhq.server.storage.maintenance.step.UpdateStorageNodeEntity;

/**
* @author Stefan Negrea
*
*/
public class StorageMaintenanceJobFactory {

private StorageMaintenanceJobFactory() {
}

public MaintenanceJob createJob(String operation, String[] existingStorageNodes, String[] affectedNodes, String args) {
MaintenanceJob job = new MaintenanceJob();

job.setType(1);
job.setName(operation);

if (operation.equals("NodeChangeAddress")) {
job.setSteps(createNodeChangeAddressSteps(job, existingStorageNodes, affectedNodes));
}

return job;
}

public List<MaintenanceStep> createNodeChangeAddressSteps(MaintenanceJob job, String[] existingNodes,
String[] affectedNodes) {

List<MaintenanceStep> steps = new ArrayList<MaintenanceStep>();

if (existingNodes.length == 1) {
int stepCount = 0;

MaintenanceStepFacade stepBuilder = new UpdateStorageNodeEntity();
steps.add(stepBuilder.build(job, stepCount++, existingNodes, affectedNodes[0]));

stepBuilder = new ShutdownStorageClient();
steps.add(stepBuilder.build(job, stepCount++, existingNodes, affectedNodes[0]));

stepBuilder = new UpdateStorageNodeEndpoints();
steps.add(stepBuilder.build(job, stepCount++, existingNodes, affectedNodes[0]));

stepBuilder = new StartStorageClient();
steps.add(stepBuilder.build(job, stepCount++, existingNodes, affectedNodes[0]));
}

return steps;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* RHQ Management Platform
* Copyright (C) 2005-2014 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.server.storage.maintenance.step;

import org.rhq.core.domain.storage.MaintenanceJob;
import org.rhq.core.domain.storage.MaintenanceStep;

/**
* @author Stefan Negrea
*
*/
public interface MaintenanceStepFacade {

void execute(MaintenanceStep maintenanceStep) throws Exception;

MaintenanceStep build(MaintenanceJob job, int stepNumber, String[] existingNodes, String affectedNode);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* RHQ Management Platform
* Copyright (C) 2005-2014 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.server.storage.maintenance.step;

import javax.ejb.EJB;

import org.rhq.core.domain.storage.MaintenanceJob;
import org.rhq.core.domain.storage.MaintenanceStep;
import org.rhq.core.domain.storage.MaintenanceStep.Type;
import org.rhq.enterprise.server.storage.StorageClientManager;

/**
* @author Stefan Negrea
*
*/
public class ShutdownStorageClient implements MaintenanceStepFacade {

@EJB
private StorageClientManager storageClientManager;

@Override
public void execute(MaintenanceStep maintenanceStep) {
storageClientManager.shutdown();
}

@Override
public MaintenanceStep build(MaintenanceJob job, int stepNumber, String[] existingNodes, String affectedNode) {
MaintenanceStep step = new MaintenanceStep();

step.setStep(stepNumber)
.setName(ShutdownStorageClient.class.getSimpleName())
.setType(Type.ServerUpdate)
.setSequential(true)
.setTimeout(1000)
.setMaintenanceJob(job);

return step;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* RHQ Management Platform
* Copyright (C) 2005-2014 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.server.storage.maintenance.step;

import javax.ejb.EJB;

import org.rhq.core.domain.storage.MaintenanceJob;
import org.rhq.core.domain.storage.MaintenanceStep;
import org.rhq.core.domain.storage.MaintenanceStep.Type;
import org.rhq.enterprise.server.storage.StorageClientManager;

/**
* @author Stefan Negrea
*
*/
public class StartStorageClient implements MaintenanceStepFacade {

@EJB
private StorageClientManager storageClientManager;

@Override
public void execute(MaintenanceStep maintenanceStep) {
storageClientManager.init();
}

@Override
public MaintenanceStep build(MaintenanceJob job, int stepNumber, String[] existingNodes, String affectedNode) {
MaintenanceStep step = new MaintenanceStep();

step.setStep(stepNumber)
.setName(StartStorageClient.class.getSimpleName())
.setType(Type.ServerUpdate)
.setSequential(true)
.setTimeout(1000)
.setMaintenanceJob(job);

return step;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* RHQ Management Platform
* Copyright (C) 2005-2014 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.server.storage.maintenance.step;

import javax.ejb.EJB;

import org.rhq.core.domain.cloud.StorageNode;
import org.rhq.core.domain.common.JobTrigger;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.criteria.ResourceOperationHistoryCriteria;
import org.rhq.core.domain.operation.OperationRequestStatus;
import org.rhq.core.domain.operation.ResourceOperationHistory;
import org.rhq.core.domain.operation.bean.ResourceOperationSchedule;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.storage.MaintenanceJob;
import org.rhq.core.domain.storage.MaintenanceStep;
import org.rhq.core.domain.storage.MaintenanceStep.Type;
import org.rhq.core.domain.util.PageControl;
import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.server.auth.SubjectManagerBean;
import org.rhq.enterprise.server.cloud.StorageNodeManagerBean;
import org.rhq.enterprise.server.operation.OperationManagerBean;

/**
* @author Stefan Negrea
*
*/
public class UpdateStorageNodeEndpoints implements MaintenanceStepFacade {

@EJB
private StorageNodeManagerBean storageNodeManager;

@EJB
private SubjectManagerBean subjectManager;

@EJB
private OperationManagerBean operationManager;

@Override
public void execute(MaintenanceStep maintenanceStep) throws Exception {

StorageNode storageNode = storageNodeManager.findStorageNodeByAddress(maintenanceStep.getNodeAddress());
Resource storageNodeResource = storageNode.getResource();
//scheduling the operation
long operationStartTime = System.currentTimeMillis();

ResourceOperationSchedule newSchedule = new ResourceOperationSchedule();
newSchedule.setJobTrigger(JobTrigger.createNowTrigger());
newSchedule.setResource(storageNodeResource);
newSchedule.setOperationName("updateEndpoints");
newSchedule.setDescription("Run by StorageNodeManagerBean");
newSchedule.setParameters(new Configuration());

storageNodeManager.scheduleOperationInNewTransaction(subjectManager.getOverlord(), newSchedule);

//waiting for the operation result then return it
int iteration = 0;
boolean successResultFound = false;
while (iteration < 10 && !successResultFound) {
ResourceOperationHistoryCriteria criteria = new ResourceOperationHistoryCriteria();
criteria.addFilterResourceIds(storageNodeResource.getId());
criteria.addFilterStartTime(operationStartTime);
criteria.addFilterOperationName("updateEndpoints");
criteria.addFilterStatus(OperationRequestStatus.SUCCESS);
criteria.setPageControl(PageControl.getUnlimitedInstance());

PageList<ResourceOperationHistory> results = operationManager.findResourceOperationHistoriesByCriteria(
subjectManager.getOverlord(), criteria);

if (results != null && results.size() > 0) {
successResultFound = true;
}

if (successResultFound) {
break;
} else {
try {
Thread.sleep(100);
} catch (Exception e) {
}
}

iteration++;
}

if (!successResultFound) {
throw new Exception();
}
}

@Override
public MaintenanceStep build(MaintenanceJob job, int stepNumber, String[] existingNodes, String affectedNode) {
MaintenanceStep step = new MaintenanceStep();
step.setStep(stepNumber)
.setName(UpdateStorageNodeEndpoints.class.getSimpleName())
.setNodeAddress(affectedNode)
.setType(Type.ResourceOperation)
.setSequential(true)
.setTimeout(1000)
.setMaintenanceJob(job);

return step;
}

}

1 comment on commit 0f1b326

@jsanda
Copy link
Contributor

@jsanda jsanda commented on 0f1b326 Jul 25, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some things we need to discuss and change. First, this commit introduces a circular dependency at compile time. We already have a server/jar --> storage-maintenance maven dependency, and now we have a storage-maintenance --> server/jar dependency. That won't work.

I am -1 on StorageMaintenanceJobFactory as it exists so far. We can separate and decouple the code for building jobs, i.e., the job builder from the factory that produces the job builders. This provides a better separation of concerns that facilitates testing and makes it easier for the code to evolve independently.

MaintenanceStep.nodeAddress should be replaced with the StorageNode for a couple reasons. First, since the address can change, future jobs could break as they would no longer have the right address. Secondly, we need the StorageNode and its associated resource for executing operations.

I think that the JPA mapping for MaintenanceJob.steps is slightly wrong. I think it is missing an @OrderColumn. Without it, I do not think that order will necessarily be preserved.

The MaintenanceStepFacade impls have EJB dependencies. I don't think this will work since they are neither EJBs themselves nor CDI beans. And we unfortunately still cannot use CDI. They also do not store the arguments for the resource or server operation to be executed.

UpdateStorageNodeEndpoints has a bunch of code for executing and waiting for the results of a resource operation. That is or should be boiler plate code. It will be necessary for a growing number of maintenance steps. This logic should be performed by StorageClusterMaintenanceManagerBean. That way it is encapsulated in a single place and the kept of the maintenance step and step building code.

I put together a small PoC jsanda@b46df40 that shows what I had in mind and addresses some of the issues I have mentioned. It uses a more strongly typed approach for executing server side operations; however, I am starting to see more benefits of an embedded script approach.

Please sign in to comment.