Java tutorial
/* * Copyright 2016 Mesosphere * * Licensed 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 com.mesosphere.dcos.cassandra.common.tasks; import com.google.inject.Inject; import com.mesosphere.dcos.cassandra.common.config.CassandraConfig; import com.mesosphere.dcos.cassandra.common.config.ExecutorConfig; import com.mesosphere.dcos.cassandra.common.util.TaskUtils; import org.apache.commons.lang3.StringUtils; import org.apache.mesos.Protos; import org.apache.mesos.Protos.DiscoveryInfo; import org.apache.mesos.Protos.Port; import org.apache.mesos.dcos.Capabilities; import org.apache.mesos.offer.VolumeRequirement; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nullable; import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.UUID; /** * CassandraDaemonTask extends CassandraTask to implement the task for a * Cassandra daemon. This is the task that starts and monitors the Cassandra * node. It is the first task launched on slave with a new executor, and it * must be running for additional tasks to run successfully on the slave. In * addition to the basic CassandraTask properties it contains the configuration * for the Cassandra node. */ public class CassandraDaemonTask extends CassandraTask { private static final Logger LOGGER = LoggerFactory.getLogger(CassandraDaemonTask.class); /** * String prefix for the CassandraDaemon task. */ public static final String NAME_PREFIX = "node-"; /** * Public node name used in VIP */ public static final String VIP_NODE_NAME = "node"; /** * Public port used in VIP */ public static final int VIP_NODE_PORT = 9042; // cassandra's default native transport port public static CassandraDaemonTask parse(final Protos.TaskInfo info) { return new CassandraDaemonTask(info); } /** * Factory for {@link CassandraDaemonTask}s. */ public static class Factory { private final Capabilities capabilities; @Inject public Factory(Capabilities capabilities) { this.capabilities = capabilities; } public CassandraDaemonTask create(final String name, final String configName, final CassandraTaskExecutor executor, final CassandraConfig config) { return new CassandraDaemonTask(name, configName, executor, config, capabilities); } public CassandraDaemonTask move(CassandraDaemonTask currentDaemon, CassandraTaskExecutor executor) { final List<Protos.Label> labelsList = currentDaemon.getTaskInfo().getLabels().getLabelsList(); String configName = ""; for (Protos.Label label : labelsList) { if ("config_target".equals(label.getKey())) { configName = label.getValue(); } } if (StringUtils.isBlank(configName)) { throw new IllegalStateException("Task should have 'config_target'"); } CassandraDaemonTask replacementDaemon = new CassandraDaemonTask(currentDaemon.getName(), configName, executor, currentDaemon.getConfig(), capabilities, currentDaemon.getData().replacing(currentDaemon.getData().getHostname())); Protos.TaskInfo taskInfo = Protos.TaskInfo.newBuilder(replacementDaemon.getTaskInfo()) .setTaskId(currentDaemon.getTaskInfo().getTaskId()).build(); return new CassandraDaemonTask(taskInfo); } public CassandraDaemonTask create(final String name, final String configName, final CassandraTaskExecutor executor, final CassandraConfig config, final CassandraData data) { return new CassandraDaemonTask(name, configName, executor, config, capabilities, data); } } private static CassandraConfig updateConfig(final CassandraMode mode, final CassandraConfig config) { // If the Cassandra daemon has transitioned to the NORMAL mode, remove the replaceIp so that the next // time Cassandra starts, it does not have the startup argument -Dcassandra.replace_address=<replaceIp>. if (CassandraMode.NORMAL.equals(mode)) { return config.mutable().setReplaceIp("").build(); } else { return config; } } /** * Constructs a new CassandraDaemonTask. * * @param name The name of the Cassandra node. * @param executor The exeuctor for the CassandraDaemonTask. * @param config The configuration for the Cassandra node. */ private CassandraDaemonTask(final String name, final String configName, final CassandraTaskExecutor executor, final CassandraConfig config, final Capabilities capabilities, final CassandraData data) { super(name, configName, executor, config.getCpus(), config.getMemoryMb(), config.getDiskMb(), VolumeRequirement.VolumeMode.CREATE, config.getDiskType(), Arrays.asList(config.getJmxPort(), config.getApplication().getStoragePort(), config.getApplication().getSslStoragePort(), config.getApplication().getRpcPort(), config.getApplication().getNativeTransportPort()), getDiscoveryInfo(config.getPublishDiscoveryInfo(), config.getApplication().getClusterName(), capabilities, name, config.getApplication().getNativeTransportPort()), data); } private CassandraDaemonTask(final String name, final String configName, final CassandraTaskExecutor executor, final CassandraConfig config, final Capabilities capabilities) { this(name, configName, executor, config, capabilities, CassandraData.createDaemonData("", CassandraMode.STARTING, config)); } private CassandraDaemonTask(final Protos.TaskInfo info) { super(info); } /** * Gets the CassandraConfig for the Cassandra daemon. * * @return The configuration object for the Cassandra daemon. */ public CassandraConfig getConfig() { return getData().getConfig(); } public CassandraMode getMode() { return getData().getMode(); } @Override public CassandraDaemonTask update(CassandraTaskStatus status) { if (status.getType() == TYPE.CASSANDRA_DAEMON && status.getId().equals(getId())) { CassandraDaemonStatus daemonStatus = (CassandraDaemonStatus) status; return new CassandraDaemonTask(Protos.TaskInfo .newBuilder(getTaskInfo()).setData(getData().updateDaemon(daemonStatus.getState(), daemonStatus.getMode(), updateConfig(daemonStatus.getMode(), getConfig())).getBytes()) .build()); } return this; } @Override public CassandraDaemonTask update(Protos.TaskState state) { return new CassandraDaemonTask(getBuilder().setData(getData().withState(state).getBytes()).build()); } public CassandraDaemonStatus createStatus(Protos.TaskState state, CassandraMode mode, Optional<String> message) { return CassandraDaemonStatus.create(getStatusBuilder(state, message) .setData(CassandraData.createDaemonStatusData(mode).getBytes()).build()); } public String getVolumePath() { return TaskUtils.getVolumePaths(getTaskInfo().getResourcesList()).get(0); } @Override public CassandraDaemonStatus createStatus(Protos.TaskState state, Optional<String> message) { return createStatus(state, getMode(), message); } @Override public CassandraDaemonTask update(Protos.Offer offer) { return new CassandraDaemonTask(getBuilder().setData(getData().withHostname(offer.getHostname()).getBytes()) .setSlaveId(offer.getSlaveId()).build()); } public CassandraDaemonTask updateConfig(CassandraConfig cassandraConfig, ExecutorConfig executorConfig, UUID targetConfigName) { LOGGER.info("Updating config for task: {} to config: {}", getTaskInfo().getName(), targetConfigName.toString()); final Protos.Label label = Protos.Label.newBuilder().setKey("config_target") .setValue(targetConfigName.toString()).build(); return new CassandraDaemonTask(getBuilder() .setExecutor(getExecutor().update(executorConfig).getExecutorInfo()).setTaskId(createId(getName())) .setData(getData().withNewConfig(cassandraConfig).getBytes()).clearResources() .addAllResources(TaskUtils.updateResources(cassandraConfig.getCpus(), cassandraConfig.getMemoryMb(), getTaskInfo().getResourcesList())) .clearLabels().setLabels(Protos.Labels.newBuilder().addLabels(label).build()).build()); } @Override public CassandraDaemonTask updateId() { return new CassandraDaemonTask( getBuilder().setTaskId(createId(getName())).setExecutor(getExecutor().clearId().getExecutorInfo()) .setData(getData().withState(Protos.TaskState.TASK_STAGING).getBytes()).build()); } @Nullable private static DiscoveryInfo getDiscoveryInfo(boolean publishDiscoveryInfo, String clusterName, Capabilities capabilities, String nodeName, int nativePort) { // If the explicit configuration flag for publishing discovery info is set, include the cluster name in the // discovery info name and don't use labels. if (publishDiscoveryInfo) { DiscoveryInfo.Builder discoveryBuilder = DiscoveryInfo.newBuilder() .setVisibility(DiscoveryInfo.Visibility.EXTERNAL).setName(clusterName + "." + nodeName); discoveryBuilder.getPortsBuilder().addPortsBuilder().setName("NativeTransport").setNumber(nativePort); return discoveryBuilder.build(); } // Else, check if DC/OS has the right capabilities and publish the discovery info the DC/OS way. try { if (!capabilities.supportsNamedVips()) { return null; } } catch (Exception e) { LOGGER.warn("Unable to determine Named VIP support, assuming they are unavailable.", e); return null; } DiscoveryInfo.Builder discoveryBuilder = DiscoveryInfo.newBuilder() .setVisibility(DiscoveryInfo.Visibility.EXTERNAL).setName(nodeName); Port.Builder portBuilder = discoveryBuilder.getPortsBuilder().addPortsBuilder().setNumber(nativePort) .setProtocol("tcp"); portBuilder.getLabelsBuilder().addLabelsBuilder().setKey("VIP_" + UUID.randomUUID()) .setValue(String.format("%s:%d", VIP_NODE_NAME, VIP_NODE_PORT)); return discoveryBuilder.build(); } }