blob: af321199bdf2708ce7bcfed200b95ef25cae13f1 [file] [log] [blame]
/*
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.hadoop.ozone.om;
import org.apache.hadoop.hdds.StringUtils;
import org.apache.hadoop.hdds.cli.GenericCli;
import org.apache.hadoop.hdds.cli.HddsVersionProvider;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.tracing.TracingUtil;
import org.apache.hadoop.ozone.util.OzoneNetUtils;
import org.apache.hadoop.ozone.util.OzoneVersionInfo;
import org.apache.hadoop.ozone.util.ShutdownHookManager;
import org.apache.hadoop.security.authentication.client.AuthenticationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import java.io.IOException;
import static org.apache.hadoop.ozone.conf.OzoneServiceConfig.DEFAULT_SHUTDOWN_HOOK_PRIORITY;
/**
* This class provides a command line interface to start the OM
* using Picocli.
*/
@Command(name = "ozone om",
hidden = true, description = "Start or initialize the Ozone Manager.",
versionProvider = HddsVersionProvider.class,
mixinStandardHelpOptions = true)
public class OzoneManagerStarter extends GenericCli {
private OzoneConfiguration conf;
private OMStarterInterface receiver;
private static final Logger LOG =
LoggerFactory.getLogger(OzoneManagerStarter.class);
public static void main(String[] args) throws Exception {
OzoneNetUtils.disableJvmNetworkAddressCacheIfRequired(
new OzoneConfiguration());
new OzoneManagerStarter(
new OzoneManagerStarter.OMStarterHelper()).run(args);
}
public OzoneManagerStarter(OMStarterInterface receiverObj) {
receiver = receiverObj;
}
@Override
public Void call() throws Exception {
/**
* This method is invoked only when a sub-command is not called. Therefore
* if someone runs "ozone om" with no parameters, this is the method
* which runs and starts the OM.
*/
try {
commonInit();
startOm();
} catch (Exception ex) {
LOG.error("OM start failed with exception", ex);
throw ex;
}
return null;
}
/**
* This function is used by the command line to start the OM.
*/
private void startOm() throws Exception {
receiver.start(conf);
}
/**
* This function implements a sub-command to allow the OM to be
* initialized from the command line.
*/
@CommandLine.Command(name = "--init",
customSynopsis = "ozone om [global options] --init",
hidden = false,
description = "Initialize the Ozone Manager if not already initialized",
mixinStandardHelpOptions = true,
versionProvider = HddsVersionProvider.class)
public void initOm()
throws Exception {
commonInit();
boolean result = receiver.init(conf);
if (!result) {
throw new IOException("OM Init failed.");
}
}
/**
* This function implements a sub-command to allow the OM to be
* Removed from prepare mode after an upgrade or downgrade.
*/
@CommandLine.Command(name = "--upgrade",
aliases = "--downgrade",
customSynopsis = "ozone om [global options] --upgrade",
description = "Cancels prepare state in this OM on startup",
mixinStandardHelpOptions = true,
versionProvider = HddsVersionProvider.class)
public void startOmUpgrade() throws Exception {
try {
commonInit();
receiver.startAndCancelPrepare(conf);
} catch (Exception ex) {
LOG.error("Cancelling prepare to start OM in upgrade mode failed " +
"with exception", ex);
throw ex;
}
}
/**
* This function implements a sub-command to allow the OM to be bootstrapped
* from the command line.
*
* During initialization, OM will get the metadata information from all the
* other OMs to check whether their on disk configs have been updated with
* this new OM information. If not, the bootstrap step will fail. This
* check is skipped with the --force option.
* Note that if an OM does not have updated configs, it can crash when a
* force bootstrap is initiated. The force option is provided for the
* scenario where one of the old OMs is down or not responding and the
* bootstrap needs to continue.
*
* Bootstrapping OM will request the leader OM to add itself to the ring.
* Once the leader OM responds back affirmatively, bootstrap step is
* complete and the OM is functional.
*/
@CommandLine.Command(name = "--bootstrap",
customSynopsis = "ozone om [global options] --bootstrap [options]",
hidden = false,
description = "Initializes and Bootstraps the Ozone Manager.",
mixinStandardHelpOptions = true,
versionProvider = HddsVersionProvider.class)
public void bootstrapOM(@CommandLine.Option(names = {"--force"},
description = "This option will skip checking whether existing OMs " +
"configs have been updated with the new OM information. Force " +
"bootstrap can cause an existing OM to crash if it does not have " +
"updated configs. It should only be used if an existing OM is down " +
"or not responding and after manually checking that the ozone-site" +
".xml config is updated on all OMs.",
defaultValue = "false") boolean force)
throws Exception {
commonInit();
receiver.bootstrap(conf, force);
}
/**
* This function should be called by each command to ensure the configuration
* is set and print the startup banner message.
*/
private void commonInit() {
conf = createOzoneConfiguration();
TracingUtil.initTracing("OzoneManager", conf);
String[] originalArgs = getCmd().getParseResult().originalArgs()
.toArray(new String[0]);
StringUtils.startupShutdownMessage(OzoneVersionInfo.OZONE_VERSION_INFO,
OzoneManager.class, originalArgs, LOG);
}
/**
* This static class wraps the external dependencies needed for this command
* to execute its tasks. This allows the dependency to be injected for unit
* testing.
*/
static class OMStarterHelper implements OMStarterInterface {
@Override
public void start(OzoneConfiguration conf) throws IOException,
AuthenticationException {
OzoneManager om = OzoneManager.createOm(conf);
om.start();
ShutdownHookManager.get().addShutdownHook(() -> {
try {
om.stop();
om.join();
} catch (Exception e) {
LOG.error("Error during stop OzoneManager.", e);
}
}, DEFAULT_SHUTDOWN_HOOK_PRIORITY);
}
@Override
public boolean init(OzoneConfiguration conf) throws IOException,
AuthenticationException {
return OzoneManager.omInit(conf);
}
@Override
public void bootstrap(OzoneConfiguration conf, boolean force)
throws IOException, AuthenticationException {
// Initialize the Ozone Manager, if not already initialized.
boolean initialize = OzoneManager.omInit(conf);
if (!initialize) {
throw new IOException("OM Init failed.");
}
OzoneManager.StartupOption startupOption;
if (force) {
startupOption = OzoneManager.StartupOption.FORCE_BOOTSTRAP;
} else {
startupOption = OzoneManager.StartupOption.BOOTSTRAP;
}
// Bootstrap the OM
try (OzoneManager om = OzoneManager.createOm(conf, startupOption)) {
om.start();
om.join();
}
}
@Override
public void startAndCancelPrepare(OzoneConfiguration conf)
throws IOException, AuthenticationException {
try (OzoneManager om = OzoneManager.createOm(conf)) {
om.getPrepareState().cancelPrepare();
om.start();
om.join();
}
}
}
}