org.apache.bookkeeper.stream.cli.commands.cluster.InitClusterCommand.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.bookkeeper.stream.cli.commands.cluster.InitClusterCommand.java

Source

/*
 * 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.bookkeeper.stream.cli.commands.cluster;

import static com.google.common.base.Preconditions.checkArgument;
import static org.apache.bookkeeper.stream.cli.Commands.OP_INIT;

import com.beust.jcommander.Parameter;
import com.google.common.base.Strings;
import com.google.common.util.concurrent.UncheckedExecutionException;
import java.net.URI;
import lombok.extern.slf4j.Slf4j;
import org.apache.bookkeeper.common.net.ServiceURI;
import org.apache.bookkeeper.conf.ServerConfiguration;
import org.apache.bookkeeper.meta.MetadataDrivers;
import org.apache.bookkeeper.stream.cli.commands.cluster.InitClusterCommand.Flags;
import org.apache.bookkeeper.stream.storage.StorageConstants;
import org.apache.bookkeeper.stream.storage.impl.cluster.ZkClusterInitializer;
import org.apache.bookkeeper.tools.common.BKCommand;
import org.apache.bookkeeper.tools.common.BKFlags;
import org.apache.bookkeeper.tools.framework.CliFlags;
import org.apache.bookkeeper.tools.framework.CliSpec;
import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.lang3.StringUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.BoundedExponentialBackoffRetry;
import org.apache.distributedlog.exceptions.ZKException;
import org.apache.distributedlog.impl.metadata.BKDLConfig;
import org.apache.distributedlog.metadata.DLMetadata;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.Code;

/**
 * Command to init a cluster.
 */
@Slf4j
public class InitClusterCommand extends BKCommand<Flags> {

    private static final String NAME = OP_INIT;
    private static final String DESC = "Init a cluster";

    /**
     * Flags for the init cluster command.
     */
    public static class Flags extends CliFlags {

        @Parameter(names = { "-x",
                "--cluster-name" }, description = "cluster name. this would be used as a root path for storing metadata.")
        private String clusterName = "";

        @Parameter(names = { "-l", "--ledgers-path" }, description = "root path to store ledgers' metadata")
        private String ledgersPath = "/ledgers";

        @Parameter(names = { "-dl", "--dlog-path" }, description = "root path to store dlog metadata")
        private String dlogPath = "/distributedlog";

        @Parameter(names = { "-n",
                "--num-storage-containers" }, description = "num of storage containers allocated for stream storage")
        private int numStorageContainers = 32;

    }

    public InitClusterCommand() {
        super(CliSpec.<Flags>newBuilder().withName(NAME).withDescription(DESC).withFlags(new Flags())
                .withUsage("bkctl cluster init [flags] <service-uri>").build());
    }

    @Override
    protected boolean acceptServiceUri(ServiceURI serviceURI) {
        // only support zookeeper now
        return ServiceURI.SERVICE_ZK.equals(serviceURI.getServiceName());
    }

    @Override
    protected boolean apply(ServiceURI ignored, CompositeConfiguration conf, BKFlags globalFlags, Flags cmdFlags) {
        checkArgument(!cmdFlags.arguments.isEmpty(), "No service URI is provided");

        ServiceURI serviceURI = ServiceURI.create(cmdFlags.arguments.get(0));

        if (null != cmdFlags.clusterName) {
            checkArgument(!cmdFlags.clusterName.contains("/"), "Invalid cluster name : " + cmdFlags.clusterName);
        }

        checkArgument(!Strings.isNullOrEmpty(cmdFlags.ledgersPath) && cmdFlags.ledgersPath.startsWith("/"),
                "Invalid ledgers root metadata path : " + cmdFlags.ledgersPath);

        checkArgument(!Strings.isNullOrEmpty(cmdFlags.dlogPath) && cmdFlags.dlogPath.startsWith("/"),
                "Invalid dlog root metadata path : " + cmdFlags.dlogPath);

        checkArgument(cmdFlags.numStorageContainers > 0,
                "Zero or negative number of storage containers configured");

        String clusterName = null == cmdFlags.clusterName ? "" : cmdFlags.clusterName;
        String ledgersPath = getFullyQualifiedPath(clusterName, cmdFlags.ledgersPath);
        String dlogPath = getFullyQualifiedPath(clusterName, cmdFlags.dlogPath);

        String metadataServiceHosts = StringUtils.join(serviceURI.getServiceHosts(), ",");

        try (CuratorFramework client = CuratorFrameworkFactory.newClient(metadataServiceHosts,
                new BoundedExponentialBackoffRetry(100, 10000, 20))) {
            client.start();

            URI uri = serviceURI.getUri();
            URI rootUri = new URI(uri.getScheme(), uri.getAuthority(), "", null, null);

            String ledgersUri = rootUri.toString() + ledgersPath;
            String dlogUri = rootUri.toString() + dlogPath;

            log.info("Initializing cluster {} : \n" + "\tledgers : path = {}, uri = {}\n"
                    + "\tdlog: path = {}, uri = {}\n" + "\tstream storage: path = {}, num_storage_containers = {}",
                    clusterName, ledgersPath, ledgersUri, dlogPath, dlogUri, StorageConstants.ZK_METADATA_ROOT_PATH,
                    cmdFlags.numStorageContainers);

            // create the cluster root path
            initializeCluster(client, clusterName);

            // init the ledgers metadata
            initLedgersMetadata(ledgersUri);

            // init the dlog metadata
            initDlogMetadata(client, metadataServiceHosts, dlogUri, dlogPath, ledgersPath);

            // init the stream storage metadata
            initStreamStorageMetadata(metadataServiceHosts, ledgersUri, cmdFlags.numStorageContainers);
            log.info("Successfully initialized cluster {}", clusterName);
            return true;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void initializeCluster(CuratorFramework client, String clusterName) throws Exception {
        if (Strings.isNullOrEmpty(clusterName)) {
            return;
        }

        String path = "/" + clusterName;
        if (null == client.checkExists().forPath(path)) {
            try {
                client.create().forPath(path);
            } catch (KeeperException.NodeExistsException ne) {
                // someone created it already
                return;
            }
        }
    }

    private void initLedgersMetadata(String ledgersUri) throws Exception {
        MetadataDrivers.runFunctionWithRegistrationManager(
                new ServerConfiguration().setMetadataServiceUri(ledgersUri), rm -> {
                    try {
                        if (rm.initNewCluster()) {
                            log.info("Successfully initialized ledgers metadata at {}", ledgersUri);
                        }
                    } catch (Exception e) {
                        throw new UncheckedExecutionException("Failed to init ledgers metadata at " + ledgersUri,
                                e);
                    }
                    return null;
                });
    }

    private void initDlogMetadata(CuratorFramework client, String metadataServiceHosts, String dlogUri,
            String dlogPath, String ledgersPath) throws Exception {
        BKDLConfig dlogConfig = new BKDLConfig(metadataServiceHosts, ledgersPath);
        DLMetadata dlogMetadata = DLMetadata.create(dlogConfig);

        if (null == client.checkExists().forPath(dlogPath)) {
            try {
                dlogMetadata.create(URI.create(dlogUri));
            } catch (ZKException zke) {
                if (Code.NODEEXISTS.intValue() == zke.getCode()) {
                    // dlog namespace already created
                    return;
                }
            }
        }
    }

    private void initStreamStorageMetadata(String metadataServiceHosts, String ledgersUri,
            int numStorageContainers) {
        ZkClusterInitializer initializer = new ZkClusterInitializer(metadataServiceHosts);
        if (initializer.initializeCluster(URI.create(ledgersUri), numStorageContainers)) {
            log.info("Successfully initialized stream storage metadata at {}:{}", metadataServiceHosts,
                    StorageConstants.ZK_METADATA_ROOT_PATH);
        }
    }

    private static String getFullyQualifiedPath(String clusterName, String path) {
        if (Strings.isNullOrEmpty(clusterName)) {
            clusterName = "";
        } else {
            clusterName = "/" + clusterName;
        }
        return clusterName + path;
    }

}