Skip to content

Commit 853137f

Browse files
safianalicbowend74
authored andcommitted
MB-64136 Better default paths + overrides
Previously, the default paths for the various directories were found relative to the location of couchbase-cli. This was acceptable since the commands that relied on this were only supposed to be run from the CB Server location of couchbase-cli. With the new admin-tools, this is no longer necessarily true. This change now uses the relative path if available, but if not, we fall back to the default paths. There are also documented override flags which can be used in case of a non-default installation of CB Server. Testing _______ Tested with default + non-default install + using override flags on Linux, Mac and Windows. Change-Id: I48e2aa44458fc1fa71265651f1d363320f22981c Reviewed-on: https://review.couchbase.org/c/couchbase-cli/+/219416 Tested-by: Build Bot <build@couchbase.com> Reviewed-by: Matt Hall <matt.hall@couchbase.com> Well-Formed: Restriction Checker
1 parent 9d20056 commit 853137f

6 files changed

Lines changed: 192 additions & 40 deletions

File tree

cbmgr.py

Lines changed: 130 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import tempfile
1616
import time
1717
import urllib.parse
18+
import traceback
1819
from argparse import SUPPRESS, Action, ArgumentError, ArgumentParser, HelpFormatter
1920
from operator import itemgetter
2021
from typing import Any, Dict, List, Optional
@@ -40,38 +41,102 @@
4041
BUCKET_TYPE_COUCHBASE = "membase"
4142
BUCKET_TYPE_MEMCACHED = "memcached"
4243

43-
CB_BIN_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "bin"))
44-
CB_ETC_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "etc", "couchbase"))
45-
CB_LIB_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "lib"))
4644

47-
if os.name == 'nt':
48-
CB_NS_EBIN_PATH = os.path.join(CB_LIB_PATH, "ns_server", "ebin")
49-
CB_BABYSITTER_EBIN_PATH = os.path.join(CB_LIB_PATH, "ns_babysitter", "ebin")
50-
else:
51-
CB_NS_EBIN_PATH = os.path.join(CB_LIB_PATH, "ns_server", "erlang", "lib", "ns_server", "ebin")
52-
CB_BABYSITTER_EBIN_PATH = os.path.join(CB_LIB_PATH, "ns_server", "erlang", "lib", "ns_babysitter", "ebin")
45+
def check_base_path(base_path):
46+
required_dirs = ["bin", "etc", "lib"]
47+
return all(os.path.exists(os.path.join(base_path, d)) for d in required_dirs)
5348

54-
inetrc_file = os.path.join(CB_ETC_PATH, 'hosts.cfg')
55-
if os.path.isfile(inetrc_file):
56-
inetrc_file = inetrc_file.encode('unicode-escape').decode()
57-
CB_INETRC_OPT = ['inetrc', f'"{inetrc_file}"']
58-
else:
59-
CB_INETRC_OPT = []
6049

61-
# On MacOS the config is store in the users home directory
62-
if platform.system() == "Darwin":
63-
CB_CFG_PATH = os.path.expanduser("~/Library/Application Support/Couchbase/var/lib/couchbase")
64-
# erl script fails in OSX as it is unable to find COUCHBASE_TOP
65-
os.environ["COUCHBASE_TOP"] = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
66-
else:
67-
CB_CFG_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "var", "lib", "couchbase"))
50+
def get_base_cb_path():
51+
# Check if relative path exists
52+
base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
53+
if os.path.exists(base_path) and check_base_path(base_path):
54+
return base_path
6855

69-
CB_MAN_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "share"))
56+
# If the base path is not at the relative path, then check the default path, which is platform dependent
57+
system = platform.system()
58+
if system == "Darwin":
59+
base_path = os.path.join(os.sep, "Applications", "Couchbase Server.app", "Contents", "Resources",
60+
"couchbase-core")
61+
elif system == "Windows":
62+
base_path = os.path.join("C:" + os.sep, "Program Files", "couchbase", "server")
63+
elif system == "Linux":
64+
base_path = os.path.join(os.sep, "opt", "couchbase")
65+
else:
66+
base_path = None
7067

71-
if os.name == "nt":
72-
CB_MAN_PATH = os.path.join(CB_MAN_PATH, "doc", "couchbase-cli")
73-
else:
74-
CB_MAN_PATH = os.path.join(CB_MAN_PATH, "man", "man1")
68+
if base_path and check_base_path(base_path):
69+
return base_path
70+
71+
return None
72+
73+
74+
def get_bin_path():
75+
base_path = get_base_cb_path()
76+
if not base_path:
77+
return None
78+
79+
return os.path.join(base_path, "bin")
80+
81+
82+
def get_hosts_path():
83+
base_path = get_base_cb_path()
84+
if not base_path:
85+
return None
86+
87+
hosts_path = os.path.join(base_path, "etc", "couchbase", "hosts.cfg")
88+
if os.path.isfile(hosts_path):
89+
return hosts_path
90+
91+
return None
92+
93+
94+
def get_inetrc(hosts_path):
95+
inetrc_file = hosts_path.encode('unicode-escape').decode()
96+
return ['inetrc', f'"{inetrc_file}"']
97+
98+
99+
def get_cfg_path():
100+
base_path = get_base_cb_path()
101+
if not base_path:
102+
return None
103+
104+
if platform.system() == "Darwin":
105+
return os.path.expanduser("~/Library/Application Support/Couchbase/var/lib/couchbase")
106+
107+
return os.path.join(base_path, "var", "lib", "couchbase")
108+
109+
110+
def get_lib_path():
111+
base_path = get_base_cb_path()
112+
if not base_path:
113+
return None
114+
115+
return os.path.join(base_path, "lib")
116+
117+
118+
def get_ns_ebin_path():
119+
lib_path = get_lib_path()
120+
if not lib_path:
121+
return None
122+
123+
if platform.system() == "Windows":
124+
return os.path.join(lib_path, "ns_server", "ebin")
125+
126+
return os.path.join(lib_path, "ns_server", "erlang", "lib", "ns_server", "ebin")
127+
128+
129+
def get_man_path():
130+
base_path = get_base_cb_path()
131+
if not base_path:
132+
return None
133+
134+
share_path = os.path.join(base_path, "share")
135+
136+
if platform.system() == "Windows":
137+
return os.path.join(share_path, "doc", "couchbase-cli")
138+
139+
return os.path.join(share_path, "man", "man1")
75140

76141

77142
def get_doc_page_name(command: str) -> str:
@@ -539,14 +604,15 @@ def __call__(self, parser, namespace, values, option_string=None):
539604

540605
@staticmethod
541606
def _show_man_page(page):
607+
man_path = get_man_path()
542608
if os.name == "nt":
543609
try:
544-
subprocess.call(["rundll32.exe", "url.dll,FileProtocolHandler", os.path.join(CB_MAN_PATH, page)])
610+
subprocess.call(["rundll32.exe", "url.dll,FileProtocolHandler", os.path.join(man_path, page)])
545611
except OSError as e:
546612
_exit_if_errors(["Unable to open man page using your browser, %s" % e])
547613
else:
548614
try:
549-
subprocess.call(["man", os.path.join(CB_MAN_PATH, page)])
615+
subprocess.call(["man", os.path.join(man_path, page)])
550616
except OSError:
551617
_exit_if_errors(["Unable to open man page using the 'man' command, ensure it is on your path or"
552618
+ "install a manual reader"])
@@ -742,7 +808,7 @@ def __init__(self):
742808
group.add_argument("-h", "--help", action=CBHelpAction, klass=self,
743809
help="Prints the short or long help message")
744810
group.add_argument("--config-path", dest="config_path", metavar="<path>",
745-
default=CB_CFG_PATH, help=SUPPRESS)
811+
default=get_cfg_path(), help="Overrides the default configuration path")
746812

747813
def execute(self, opts): # pylint: disable=useless-super-delegation
748814
super(LocalSubcommand, self).execute(opts)
@@ -1737,6 +1803,9 @@ def __init__(self):
17371803
help="The REST API port, defaults to 8091")
17381804

17391805
def execute(self, opts):
1806+
if opts.config_path is None:
1807+
_exit_if_errors(["Unable to locate the configuration path, please specify it using --config-path"])
1808+
17401809
token = _exit_on_file_read_failure(os.path.join(opts.config_path, "localtoken")).rstrip()
17411810
rest = ClusterManager("http://127.0.0.1:" + opts.port, "@localtoken", token)
17421811
check_cluster_initialized(rest)
@@ -1774,6 +1843,9 @@ def __init__(self):
17741843

17751844
def execute(self, opts):
17761845
if opts.send_password is not None:
1846+
if opts.config_path is None:
1847+
_exit_if_errors(["Unable to locate the configuration path, please specify it using --config-path"])
1848+
17771849
portfile = os.path.join(opts.config_path, "couchbase-server.babysitter.smport")
17781850
if not os.path.isfile(portfile):
17791851
_exit_if_errors(["The node is down"])
@@ -2078,6 +2150,9 @@ def __init__(self):
20782150
help="The IP address of the cluster, defaults to localhost")
20792151

20802152
def execute(self, opts):
2153+
if opts.config_path is None:
2154+
_exit_if_errors(["Unable to locate the configuration path, please specify it using --config-path"])
2155+
20812156
token = _exit_on_file_read_failure(os.path.join(opts.config_path, "localtoken")).rstrip()
20822157
ip = opts.ip if ":" not in opts.ip else "[" + opts.ip + "]"
20832158
rest = ClusterManager("http://" + ip + ":" + opts.port, "@localtoken", token)
@@ -2179,8 +2254,14 @@ def __init__(self):
21792254
group = self.parser.add_argument_group("Server eshell options")
21802255
group.add_argument("--vm", dest="vm", default="ns_server", metavar="<name>",
21812256
help="The vm to connect to")
2182-
group.add_argument("--erl-path", dest="erl_path", metavar="<path>", default=CB_BIN_PATH,
2183-
help="Override the path to the erl executable")
2257+
group.add_argument("--erl-path", dest="erl_path", metavar="<path>", default=get_bin_path(),
2258+
help="Override the default path to the erl executable")
2259+
group.add_argument("--ns-ebin-path", dest="ns_ebin_path", metavar="<path>", default=get_ns_ebin_path(),
2260+
help="Override the default path to the ns_server ebin directory")
2261+
group.add_argument("--hosts-path", dest="hosts_path", metavar="<path>", default=get_hosts_path(),
2262+
help="Override the default path to the hosts.cfg file")
2263+
group.add_argument("--base-path", dest="base_path", metavar="<path>", default=get_base_cb_path(),
2264+
help="Override the default path to the Couchbase Server base directory")
21842265

21852266
@rest_initialiser(version_check=True)
21862267
def execute(self, opts):
@@ -2219,12 +2300,27 @@ def execute(self, opts):
22192300
_warning("Cannot locate Couchbase erlang. Attempting to use non-Couchbase erlang")
22202301
path = 'erl'
22212302

2303+
if not opts.erl_path:
2304+
_exit_if_errors(["directory containing erl executable not found, please specify it using --erl-path"])
2305+
2306+
if not opts.ns_ebin_path:
2307+
_exit_if_errors(["ns_server ebin directory not found, please specify it using --ns-ebin-path"])
2308+
2309+
if not opts.hosts_path:
2310+
_exit_if_errors(["hosts.cfg file not found, please specify it using --hosts-path"])
2311+
2312+
if not opts.base_path:
2313+
_exit_if_errors(["Couchbase Server base directory not found, please specify it using --base-path"])
2314+
22222315
with tempfile.NamedTemporaryFile() as temp:
22232316
temp.write(f'[{{preferred_local_proto,{result["addressFamily"]}_tcp_dist}}].'.encode())
22242317
temp.flush()
22252318
temp_name = temp.name
22262319
env = os.environ.copy()
22272320
env["CB_COOKIE"] = cookie
2321+
if platform.system() == "Darwin":
2322+
# erl script fails in OSX as it is unable to find COUCHBASE_TOP
2323+
env["COUCHBASE_TOP"] = opts.base_path
22282324

22292325
args = [
22302326
path,
@@ -2243,10 +2339,10 @@ def execute(self, opts):
22432339
'cb_epmd',
22442340
'-no_epmd',
22452341
'-pa',
2246-
CB_NS_EBIN_PATH,
2342+
opts.ns_ebin_path,
22472343
'-kernel',
22482344
'dist_config_file',
2249-
f'"{temp_name}"'] + CB_INETRC_OPT
2345+
f'"{temp_name}"'] + get_inetrc(opts.hosts_path)
22502346

22512347
if opts.debug:
22522348
print(f'Running {" ".join(args)}')

docs/modules/cli/pages/cbcli/couchbase-cli-master-password.adoc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Sends the Couchbase master password
1313

1414
[verse]
1515
_couchbase-cli master-password_ [--send-password <password>]
16+
[--config-path <path>]
1617

1718
== DESCRIPTION
1819

@@ -39,6 +40,15 @@ a member of the `couchbase` group (or be root.)
3940
--send-password::
4041
Sends the master password to the server that is waiting to start up.
4142

43+
--config-path::
44+
Manually specify the path to the Couchbase Server configuration file. This
45+
is only needed if the configuration file is not in the default location,
46+
otherwise it can be found at `var/lib/couchbase` within the Couchbase
47+
Server installation directory.
48+
49+
Note: on Mac, this path is instead located in the user's home directory, at
50+
`~/Library/Application Support/Couchbase/var/lib/couchbase`.
51+
4252
== EXAMPLES
4353

4454
To use the Secret Management feature, the first thing you need to do is set a

docs/modules/cli/pages/cbcli/couchbase-cli-reset-admin-password.adoc

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Resets the Couchbase Server administrator password
1313

1414
[verse]
1515
_couchbase-cli reset-admin-password_ [--regenerate] [--new-password <password>]
16-
[--port <port>]
16+
[--port <port>] [--config-path <path>]
1717

1818
== DESCRIPTION
1919

@@ -45,6 +45,15 @@ result, the command does not require credentials to be passed.
4545
Specify the REST API port of the locally running Couchbase Server. If no
4646
port is specified the default port 8091 is used.
4747

48+
--config-path::
49+
Manually specify the path to the Couchbase Server configuration file. This
50+
is only needed if the configuration file is not in the default location,
51+
otherwise it can be found at `var/lib/couchbase` within the Couchbase
52+
Server installation directory.
53+
54+
Note: on Mac, this path is instead located in the user's home directory, at
55+
`~/Library/Application Support/Couchbase/var/lib/couchbase`.
56+
4857
== EXAMPLES
4958

5059
To change the administrator password to `new_pwd`, run the following command:

docs/modules/cli/pages/cbcli/couchbase-cli-reset-cipher-suites.adoc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Resets the Couchbase Server cipher suites to the default
1313

1414
[verse]
1515
_couchbase-cli reset-cipher-suites_ [--force] [--port <port>]
16+
[--config-path <path>]
1617

1718
== DESCRIPTION
1819

@@ -37,6 +38,15 @@ have read access to the local Couchbase Server configuration files.
3738
Specify the REST API port of the locally running Couchbase Server. If no
3839
port is specified the default port 8091 is used.
3940

41+
--config-path::
42+
Manually specify the path to the Couchbase Server configuration file. This
43+
is only needed if the configuration file is not in the default location,
44+
otherwise it can be found at `var/lib/couchbase` within the Couchbase
45+
Server installation directory.
46+
47+
Note: on Mac, this path is instead located in the user's home directory, at
48+
`~/Library/Application Support/Couchbase/var/lib/couchbase`.
49+
4050
== EXAMPLES
4151

4252
To reset the cipher suites to the default:

docs/modules/cli/pages/cbcli/couchbase-cli-server-eshell.adoc

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ Opens a shell to talk to the cluster manager process
1414
[verse]
1515
_couchbase-cli server-eshell_ [--cluster <url>] [--username <user>] [--password <password>]
1616
[--client-cert <path>] [--client-cert-password <password>] [--client-key <path>]
17-
[--client-key-password <password>] [--vm <vm_name>] [--erl <path>]
17+
[--client-key-password <password>] [--vm <vm_name>] [--erl-path <path>]
18+
[--ns-ebin-path <path>] [--hosts-path <path>] [--base-path <path>]
1819

1920
== DESCRIPTION
2021

@@ -42,10 +43,33 @@ include::{partialsdir}/cbcli/part-common-options.adoc[]
4243
and the ns_server vm corresponds to the cluster manager. By default the vm
4344
option is set to ns_server.
4445

45-
--erl::
46-
Specified the location of the erlang process. This parameter should be set
47-
if the default erlang process that is shipped with Couchbase is not the
48-
correct executable to connect to the cluster manager with.
46+
--erl-path::
47+
Specifies the location of the directory containing the erlang process. This
48+
parameter should only be set if the default erlang process that is shipped
49+
with Couchbase is not the correct executable to connect to the cluster
50+
manager with. The directory containing the erlang process is `bin` within the
51+
Couchbase Server installation directory.
52+
53+
--ns-ebin-path::
54+
Specifies the location of the ns_server ebin directory. This parameter should
55+
only be set if the default ebin directory that is shipped with Couchbase is
56+
not the correct directory to connect to the cluster manager with. The ebin
57+
directory can be found within the Couchbase Server installation directory at
58+
at `ns_server/erlang/lib/ns_server/ebin` on Mac/Linux, and `ns_server/ebin`
59+
on Windows.
60+
61+
--hosts_path::
62+
Specifies the location of the hosts.cfg file. This parameter should only be
63+
set if the default hosts.cfg file that is shipped with Couchbase is not the
64+
correct file to connect to the cluster manager with. The hosts.cfg file can
65+
be found within the Couchbase Server installation directory at
66+
`etc/couchbase/hosts.cfg`.
67+
68+
--base-path::
69+
Specifies the location of the base directory. This parameter should only be
70+
set if Couchbase was installed in a non-standard location. Note that this
71+
parameter is only currently used on Mac - on other operating systems it isn't
72+
used.
4973

5074
include::{partialsdir}/cbcli/part-host-formats.adoc[]
5175

jenkins/.aspell.en.pws

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ cbrestore
3030
cbrestorewrapper
3131
cbtransfer
3232
cbworkloadgen
33+
cfg
3334
CLI
3435
cli
3536
cmd
37+
config
3638
Couchbase
3739
couchbase
3840
couchdb
@@ -59,6 +61,7 @@ dir
5961
dn
6062
doctitle
6163
DSA
64+
ebin
6265
EE
6366
enablement
6467
erl

0 commit comments

Comments
 (0)