예제 #1
0
    def instance_admin(cls,host,realm,admin,password):
        """
        Initializes the security database of a newly initialized server.

        :param host: The name or IP address of the host to initialize
        :param realm: The security realm to install
        :param admin: The name of the admin user
        :param password: The password of the admin user
        """
        conn = Connection(host, None)

        payload = {
            'admin-username': admin,
            'admin-password': password,
            'realm': realm
            }

        uri = "{0}://{1}:8001/admin/v1/instance-admin".format(
            conn.protocol, conn.host)

        logger = logging.getLogger("marklogic")
        logger.debug("Initializing security for {0}".format(host))

        # N.B. Can't use conn.post here because we don't need auth yet
        response = requests.post(uri, json=payload,
                                 headers={'content-type': 'application/json',
                                          'accept': 'application/json'})

        if response.status_code != 202:
            raise UnexpectedManagementAPIResponse(response.text)

        # From now on connections require auth...
        conn = Connection(host, HTTPDigestAuth(admin, password))
        data = json.loads(response.text)
        conn.wait_for_restart(data["restart"]["last-startup"][0]["value"])
예제 #2
0
    def couple_cluster(self):
        conn = Connection(self.host,
                          HTTPDigestAuth(self.adminuser, self.adminpass))
        self.marklogic = MarkLogic(conn)

        if self.couple is not None:
            for couple in self.couple:
                print("{0}: couple with {1}...".format(self.host, couple))
                altconn = Connection(
                    couple, HTTPDigestAuth(self.couple_user, self.couple_pass))
                altml = MarkLogic(altconn)
                altcluster = altml.cluster()
                cluster = self.marklogic.cluster()
                cluster.couple(altcluster)

        print("Finished")
    def __init__(self, *args, **kwargs):
        super(MLConfig,self).__init__(*args, **kwargs)

        config = { "hostname": "localhost", \
                       "username": "******", \
                       "password": "******", \
                       "protocol": "http", \
                       "port": 8000, \
                       "management-port": 8002, \
                       "root": "manage", \
                       "version": "v2", \
                       "client-version": "v1" }
        try:
            data_file = open("mlconfig.json").read()
            data = json.loads(data_file)
            for key in data:
                config[key] = data[key]
        except FileNotFoundError:
            pass

        self.auth = HTTPDigestAuth(config["username"], config["password"])
        self.connection = Connection(config["hostname"], self.auth, \
                                         protocol=config["protocol"], \
                                         port=config["port"], \
                                         management_port=config["management-port"], \
                                         root=config["root"], \
                                         version=config["version"], \
                                         client_version=config["client-version"])
    def test_create_single_detailed_forest(self):
        """
        Test the following scenario:

        The database is given a forest object.  It should create a forest with
        the given name.  That forest should match the features of the datailed
        forest.

        """

        conn = Connection(tc.hostname, HTTPDigestAuth(tc.admin, tc.password))

        hosts = Host.list(conn)
        db = Database("detailed-forest-create-test-db", hosts[0])

        forest = Forest("detailed-forest-create-forest1", host=hosts[0])
        forest.set_large_data_directory(ds.large_data_directory)

        db.set_forest_names([forest.forest_name()])

        db.create(conn)

        forest = Forest.lookup(conn, "detailed-forest-create-forest1")

        try:
            self.assertEqual("detailed-forest-create-forest1",
                             forest.forest_name())
            #this isn't in the properties...oddly.
            #self.assertEqual(ds.large_data_directory, forest.large_data_directory())
        finally:
            db.delete(connection=conn)
    def test_simple_create(self):
        """
        TODO: The hostname should come from the server's hostname

        Test the basic create function.  Creates a database and then check to see that it
        exists by getting the database configuration from the server.  It then destroys
        the database.

        :return: None
        """
        conn = Connection(tc.hostname, HTTPDigestAuth(tc.admin, tc.password))
        hosts = Host.list(conn)
        db = Database("test-db", hosts[0])

        db.create(conn)

        validate_db = Database.lookup(conn, "test-db")
        try:
            self.assertIsNotNone(validate_db)
            self.assertEqual('test-db', validate_db.database_name())

        finally:
            validate_db.delete(connection=conn)
            validate_db = Database.lookup(conn, "test-db")
            self.assertIsNone(validate_db)
    def test_create_simple_forests(self):
        """
        Test the following scenario:

        The database is given the names of two forests.
        It should then create the two named forests.

        """
        conn = Connection(tc.hostname, HTTPDigestAuth(tc.admin, tc.password))

        hosts = Host.list(conn)
        db = Database("simple-forest-create-test-db",
                      hosts[0],
                      connection=conn)

        db.set_forest_names(
            ["simple-forest-create-forest1", "simple-forest-create-forest2"])

        db.create()

        db = Database.lookup(conn, "simple-forest-create-test-db")
        try:
            self.assertEqual(2, len(db.forest_names()))

            self.assertIn("simple-forest-create-forest1", db.forest_names())
            self.assertIn("simple-forest-create-forest2", db.forest_names())

        finally:
            db.delete(connection=conn)
예제 #7
0
    def instance_init(cls, host):
        """
        Performs first-time initialization of a newly installed server.

        :param host: The name or IP address of the host to initialize
        """
        conn = Connection(host, None)

        uri = "{0}://{1}:8001/admin/v1/init".format(conn.protocol, conn.host)

        logger = logging.getLogger("marklogic")
        logger.debug("Initializing {0}".format(host))

        # This call is a little odd; we special case the 400 error that
        # occurs if the host has alreadya been initialized.
        try:
            response = conn.post(
                uri, content_type='application/x-www-form-urlencoded')
        except UnexpectedManagementAPIResponse:
            response = conn.response
            if response.status_code == 400:
                err = json.loads(response.text)
                if "errorResponse" in err:
                    if "messageCode" in err["errorResponse"]:
                        if err["errorResponse"][
                                "messageCode"] == "MANAGE-ALREADYINIT":
                            return Host(host)
            raise

        if response.status_code != 202:
            raise UnexpectedManagementAPIResponse(response.text)

        return Host(host)._set_just_initialized()
    def join_cluster(self, cluster, cluster_connection=None):
        if cluster_connection is None:
            cluster_connection = cluster.connection

        xml = self._get_server_config()
        cfgzip = cluster._post_server_config(xml, cluster_connection)
        connection = Connection(self.host_name(), cluster_connection.auth)
        self._post_cluster_config(cfgzip, connection)
    def test_list_databases(self):
        conn = Connection(tc.hostname, HTTPDigestAuth(tc.admin, tc.password))
        db_names = Database.list(conn)

        self.assertGreater(len(db_names), 4)

        self.assertTrue("Modules" in db_names)
        self.assertTrue("Documents" in db_names)
예제 #10
0
    def add_host(self, host, connection=None):
        if connection is None:
            connection = self.connection

        if isinstance(host, str):
            host = Host(host)

        xml = host._get_server_config()
        cfgzip = self._post_server_config(xml,connection)

        host_connection = Connection(host.host_name(), connection.auth)
        host._post_cluster_config(cfgzip,host_connection)
    def load_data(self):
        simpleapp = SimpleApplication(tc.appname, tc.port)

        conn = Connection(tc.hostname, HTTPDigestAuth(tc.admin, tc.password))
        hostname = Host.list(conn)[0]
        exampleapp = simpleapp.create(conn, hostname)

        loader = MLCPLoader()
        loader.load_directory(conn,
                              exampleapp['content'],
                              "data",
                              collections=["example1"],
                              prefix="/test/data1")
    def setup_cluster(self):
        if self.couple is not None and self.couple_pass is None:
            self.couple_pass = self.adminpass
            self.couple_user = self.adminuser

        if self.boothost is None:
            self.boothost = self.host[0]
            self.host.remove(self.boothost)

        if self.ml_init(self.boothost):
            self.ml_security(self.boothost)

        conn = Connection(self.boothost,
                          HTTPDigestAuth(self.adminuser, self.adminpass))
        self.marklogic = MarkLogic(conn)

        for hostname in self.host:
            self.ml_init(hostname)
            self.ml_join(self.boothost, hostname)

        if self.name is not None:
            print("{0}: rename cluster...".format(self.boothost))
            cluster = self.marklogic.cluster()
            cluster.set_cluster_name(self.name)
            cluster.update()

        if self.couple is not None:
            for couple in self.couple:
                print("{0}: couple with {1}...".format(self.boothost, couple))
                altconn = Connection(
                    couple, HTTPDigestAuth(self.couple_user, self.couple_pass))
                altml = MarkLogic(altconn)
                altcluster = altml.cluster()
                cluster = self.marklogic.cluster()
                cluster.couple(altcluster)

        print("Finished")
    def _get_server_config(self):
        """
        Obtain the server configuration. This is the data necessary for
        the first part of the handshake necessary to join a host to a
        cluster. The returned data is not intended for introspection.

        :return: The config. This is always XML.
        """
        connection = Connection(self.host_name(), None)
        uri = "http://{0}:8001/admin/v1/server-config".format(connection.host)
        response = connection.get(uri, accept="application/xml")
        if response.status_code != 200:
            raise UnexpectedManagementAPIResponse(response.text)

        return response.text  # this is always XML
    def couple(self, args, config, connection):
        cluster = LocalCluster(connection=connection)
        cluster.read()

        try:
            username, password = re.split(":", args['couple_credentials'])
        except ValueError:
            print("--couple-credentials value must be 'user:password':",
                  args['couple_credentials'])
            sys.exit(1)

        altconn = Connection(args['host'], HTTPDigestAuth(username, password))
        altcluster = LocalCluster(connection=altconn)

        cluster.couple(altcluster,
                       connection=connection,
                       other_cluster_connection=altconn)
예제 #15
0
    def connect(self, args):
        try:
            adminuser, adminpass = re.split(":", args['credentials'])
        except ValueError:
            print("--credentials value must be 'user:password':"******"requests").setLevel(logging.WARNING)
            logging.getLogger("marklogic").setLevel(logging.DEBUG)

        self.connection \
          = Connection(args['hostname'], HTTPDigestAuth(adminuser, adminpass))
        self.mls = MarkLogic(self.connection)
        self.args = args
예제 #16
0
    def test_list_hosts(self):
        conn = Connection(tc.hostname, HTTPDigestAuth(tc.admin, tc.password))

        hosts = Host.list(conn)
        self.assertGreater(len(hosts), 0)
        self.assertIsNotNone(hosts[0])
        self.logger.info("Create simple application")
        data_database = Database(self._db_name, hostname)
        data_database.set_forest_names(self._forests)

        modules_database = Database(self._modules_db_name, hostname)

        server = HttpServer(self._http_server, "Default",
                            self._app_port, self._db_name, self._modules_db_name)
        server.set_modules_database_name(self._modules_db_name)

        data_database.create(conn)
        modules_database.create(conn)
        server.create(conn)

        return {
            u'content': data_database,
            u'modules': modules_database,
            u'server': server
        }

if __name__ == "__main__":
    logging.basicConfig(level=logging.WARNING)
    logging.getLogger("requests").setLevel(logging.WARNING)
    logging.getLogger("marklogic").setLevel(logging.DEBUG)
    logging.getLogger("marklogic.examples").setLevel(logging.INFO)

    simpleapp = SimpleApplication(tc.appname, tc.port)
    conn = Connection(tc.hostname, HTTPDigestAuth(tc.admin, tc.password))
    hostname = Host.list(conn)[0]
    myapp = simpleapp.create(conn, hostname)
예제 #18
0
    def setup_cluster(self):
        if self.couple is not None and self.couple_pass is None:
            self.couple_pass = self.adminpass
            self.couple_user = self.adminuser

        self.load_blacklist()
        self.find_containers()

        if not self.container_list:
            print("There must be at least one unused container running.")
            sys.exit(1)

        if self.localimage:
            ps = os.popen("docker exec " + self.container_list[0] +
                          " ip route")
            for line in ps.readlines():
                match = re.match("^default via (\S+)", line)
                if match:
                    self.localip = match.group(1)
            if self.localip is None:
                print("Cannot find IP address of localhost!?")
                sys.exit(1)

        # Find the bootstrap image

        if self.localimage:
            pass
        else:
            self.bootimage = self.pick_image(self.bootimage)
            if self.bootimage in self.container_list:
                self.container_list.remove(self.bootimage)

        self.cluster_list = self.pick_containers()

        self.display_info()
        #sys.exit(1)

        # Initialize the bootstrap image, if necessary

        if self.localimage:
            bootip = self.localip
        else:
            bootip = self.ipaddr[self.bootimage]

        if self.ml_init(bootip, self.bootimage):
            self.ml_security(bootip, self.bootimage)

        conn = Connection(bootip, HTTPDigestAuth(self.adminuser,
                                                 self.adminpass))
        self.marklogic = MarkLogic(conn)

        for container in self.cluster_list:
            if container == self.bootimage:
                continue
            ip = self.ipaddr[container]
            self.ml_init(ip, container)
            self.ml_join(bootip, ip)

        if self.name is not None:
            print("{0}: rename cluster...".format(bootip))
            cluster = self.marklogic.cluster()
            cluster.set_cluster_name(self.name)
            cluster.update()

        if self.couple is not None:
            for couple in self.couple:
                print("{0}: couple with {1}...".format(bootip, couple))
                altconn = Connection(
                    couple, HTTPDigestAuth(self.couple_user, self.couple_pass))
                altml = MarkLogic(altconn)
                altcluster = altml.cluster()
                cluster = self.marklogic.cluster()
                cluster.couple(altcluster)

        print("Finished")
예제 #19
0
    def connect(self, args):
        """Connect to the server"""
        self.path = os.path.abspath(args['path'])
        self.loadconfig(self.path)

        if args['credentials'] is not None:
            cred = args['credentials']
        else:
            if 'user' in self.config and 'pass' in self.config:
                cred = self.config['user'] + ":" + self.config['pass']
            else:
                cred = None

        try:
            adminuser, adminpass = re.split(":", cred)
        except ValueError:
            raise RuntimeError("Invalid credentials (must be user:pass): {}" \
                                   .format(args['credentials']))

        if args['debug']:
            logging.basicConfig(level=logging.WARNING)
            logging.getLogger("requests").setLevel(logging.INFO)
            logging.getLogger("marklogic").setLevel(logging.DEBUG)

        self.batchsize = args['batchsize']
        self.database = args['database']
        self.dryrun = args['dryrun']
        self.list = args['list']
        self.mirror = args['mirror']
        self.regex = args['regex']
        self.root = args['root']
        self.threshold = args['threshold']
        self.verbose = args['verbose']

        if self.list and self.regex:
            raise RuntimeError("You must not specify both --regex and --list")

        if self.root.endswith("/"):
            self.root = self.root[0:len(self.root) - 1]

        if args['hostname'] is None:
            if 'host' in self.config:
                self.hostname = self.config['host']
                if 'port' in self.config:
                    self.port = self.config['port']
                else:
                    self.port = 8000
                if 'management-port' in self.config:
                    self.management_port = self.config['management-port']
                else:
                    self.management_port = 8002
        else:
            parts = args['hostname'].split(":")
            self.hostname = parts.pop(0)
            self.management_port = 8002
            self.port = 8000
            if parts:
                self.management_port = parts.pop(0)
            if parts:
                self.port = parts.pop(0)

        self.connection \
          = Connection(self.hostname, HTTPDigestAuth(adminuser, adminpass), \
                           port=self.port, management_port=self.management_port)

        self.utils = ClientUtils(self.connection)
    def test_no_database_found(self):
        conn = Connection(tc.hostname, HTTPDigestAuth(tc.admin, tc.password))
        db = Database.lookup(conn, "No-Such-Database")

        self.assertIsNone(db)
    def run(self, argv):
        command = None
        artifact = None

        # This is an odd program. The parser used for each line depends on
        # the command and the different parsers can be cranky about the
        # allowed order of commands, options, and parameters. So we start
        # by trying to "normalize" it all.
        options = []
        params = []
        positional = []
        optarg = False
        for tok in argv:
            if optarg:
                options.append(tok)
                optarg = False
            elif tok.startswith("-"):
                options.append(tok)
                if tok != "--debug":
                    optarg = True
            elif "=" in tok:
                params.append(tok)
            else:
                positional.append(tok)

        try:
            command = positional[0]
        except IndexError:
            print("Usage: {0} command artifact ...".format(self.script))
            sys.exit(1)

        empty_artifact_commands = {
            'start', 'status', 'stop', 'restart', 'init', 'save', 'switch',
            'clear', 'log', 'run', 'debug'
        }
        try:
            artifact = positional[1]
        except IndexError:
            if command in empty_artifact_commands:
                pass
            else:
                print("Usage: {0} command artifact ...".format(self.script))
                sys.exit(1)

        # Hack for the server case
        if artifact in ['http', 'xdbc', 'odbc', 'webdav']:
            stype = artifact
            if command == 'list':
                artifact = 'servers'
            else:
                artifact = 'server'
            positional[1] = artifact
            if positional[2] == artifact:
                del (positional[2])
            options.append("--type")
            options.append(stype)

        # Hack for the stop and restart cases
        if (command == 'stop' or command == 'restart') and artifact is None:
            positional.append('host')
            artifact = 'host'

        argv = []
        argv.extend(options)
        argv.extend(positional)
        argv.extend(params)

        templ = self.cli.command_template(command)
        if templ is None:
            print("The command '{0}' is unrecognized".format(command))
            sys.exit(1)

        if artifact is None:
            if 'parser' in templ:
                parser = templ['parser']
            else:
                print("The command '{0}' isn't recognized.".format(command))
                sys.exit(1)
        else:
            if artifact in templ:
                parser = templ[artifact]["parser"]
            else:
                print("The command '{0}' doesn't take '{1}' artifacts.".format(
                    command, artifact))
                sys.exit(1)

        args = vars(parser.parse_args(argv))

        if args['debug']:
            if args['debug'] == 'debug':
                # This is the debug command, not the debug option!
                pass
            else:
                logging.basicConfig(level=logging.WARNING)
                logging.getLogger("requests").setLevel(logging.WARNING)
                logging.getLogger("marklogic").setLevel(logging.DEBUG)
        else:
            logging.basicConfig(level=logging.INFO)
            logging.getLogger("requests").setLevel(logging.WARNING)
            logging.getLogger("marklogic").setLevel(logging.INFO)

        try:
            username, password = re.split(":", args['credentials'])
        except ValueError:
            print("--credentials value must be 'user:password':"******":")[0]
            try:
                mgmt_port = args['hostname'].split(":")[1]
            except IndexError:
                mgmt_port = 8002
            self.connection = Connection(host,
                                         HTTPDigestAuth(username, password),
                                         management_port=mgmt_port)

        # do it!
        if command == 'run':
            self.process_script(args['script'])
        else:
            if artifact is None:
                templ["code"](args, self.config, self.connection)
            else:
                templ[artifact]["code"](args, self.config, self.connection)
                    help="Password")
parser.add_argument("--json", action="store",
                    help="Name of the file containing JSON config")
parser.add_argument('--debug', action='store_true',
                    help='Enable debug logging')
args = parser.parse_args()

if args.debug:
    logging.basicConfig(level=logging.WARNING)
    logging.getLogger("requests").setLevel(logging.WARNING)
    logging.getLogger("marklogic").setLevel(logging.DEBUG)

with open(args.json) as data_file:
    data = json.load(data_file)

conn = Connection(args.host, HTTPDigestAuth(args.username, args.password))

# Create roles
for config in data['roles']:
    name = config['role-name']
    role = Role.lookup(conn, name)
    if role is None:
        print("Need to create role: {0}".format(name))
        role = Role(name)
        role.create(conn)

# Update privileges
for config in data['roles']:
    name = config['role-name']
    role = Role.unmarshal(config)
    print("Updating role: {0}".format(name))
    def backup_databases(self):
        conn = Connection(self.host,
                          HTTPDigestAuth(self.adminuser, self.adminpass))
        self.marklogic = MarkLogic(conn)

        actual_databases = self.marklogic.databases()

        if self.databases is None:
            self.databases = actual_databases

        if self.backup_root is None:
            raise UnsupportedOperation("You must specify the backup root.")

        if self.max_parallel <= 0:
            self.max_parallel = 1

        for dbname in self.databases:
            if not dbname in actual_databases:
                raise UnsupportedOperation("Database does not exist: {0}"
                                           .format(dbname))

        maxp = self.max_parallel
        running = 0
        done = False
        queue = self.databases
        status_list = {}
        min_wait = 5
        max_wait = 30
        wait_incr = 5
        wait = min_wait

        while not done:
            done = True

            while len(queue) > 0 and running < maxp:
                dbname = queue.pop(0)
                running += 1
                done = False

                print("Backing up {0}".format(dbname))
                if not self.dry_run:
                    db = self.marklogic.database(dbname)
                    bkp = db.backup(self.backup_root + dbname, connection=conn)
                    status_list[dbname] = bkp
                    response = bkp.status()
                    if response['status'] != 'in-progress':
                        print("{0}: {1}".format(dbname, response['status']))

            if self.dry_run:
                if running > 0 or len(queue) > 0:
                    print("{0} backups in dry-run; {1} in queue..."
                          .format(running, len(queue)))
                    running = 0
            else:
                if len(status_list) > 0:
                    new_list = {}
                    for dbname in status_list:
                        bkp = status_list[dbname]
                        response = bkp.status()
                        print("{0}: {1}".format(dbname, response['status']))
                        if response['status'] == 'in-progress':
                            done = False
                            new_list[dbname] = bkp
                        else:
                            running -= 1
                            wait = min_wait

                    done = done and len(queue) == 0

                    if not done:
                        status_list = new_list
                        if running < maxp and len(queue) != 0:
                            print("Running: {0} backups running; {1} in queue..."
                                  .format(running, len(queue)))
                            wait = min_wait
                            print("")
                        else:
                            print("Waiting {0}s: {1} backups running; {2} in queue..."
                                  .format(wait, running, len(queue)))
                            time.sleep(wait)
                            if wait < max_wait:
                                wait += wait_incr
                            print("")