Skip to content

Commit 13b45ae

Browse files
committed
Ready for initial release
Signed-off-by: Ole Herman Schumacher Elgesem <ole.elgesem@northern.tech>
1 parent f9fbff0 commit 13b45ae

File tree

5 files changed

+53
-220
lines changed

5 files changed

+53
-220
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ build
22
dist
33
/cfengine_cli/VERSION
44
/cfengine_cli/__pycache__/
5-
/cfengine_cli.egg-info/
5+
/cfengine.egg-info/
66
/venv
77
/.venv
88
__pycache__/

README.md

Lines changed: 21 additions & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -1,222 +1,43 @@
1-
# cf-remote
1+
# CFEngine CLI
22

3-
`cf-remote` is a tool to deploy CFEngine.
4-
It works by contacting remote hosts with SSH and using `ssh` / `scp` to copy files and run commands.
5-
Commands for provisioning hosts in the cloud (AWS or GCP) are also available.
6-
7-
## Requirements
8-
9-
- cf-remote requires python 3.6 or greater.
10-
- SSH must be configured in such a way that cf-remote can login without a password.
11-
- An sftp server for transferring files on UNIX hosts. e.g. openssh-sftp-server for debian-based distributions.
3+
A simple CLI for interacting with various CFEngine tools, such as cf-agent, cf-remote, cf-hub, cf-remote, and cfbs.
124

135
## Installation
146

15-
Install with pip3:
16-
17-
```
18-
$ pip3 install cf-remote
19-
```
20-
21-
## Examples
22-
23-
### See information about remote host
24-
25-
The `info` command can be used to check basic information about a system.
26-
The --hosts/-H option accepts [user@]hostname[:port] for the hostname.
27-
In the case that hostname is an ipv6 address use literal square brackets as described in RFC-3986 (https://www.ietf.org/rfc/rfc3986.txt)
28-
29-
e.g. user@[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:8022
30-
31-
```
32-
$ cf-remote info -H 34.241.203.218
33-
34-
ubuntu@34.241.203.218
35-
OS : ubuntu (debian)
36-
Architecture : x86_64
37-
CFEngine : 3.12.1
38-
Policy server : 172.31.42.192
39-
Binaries : dpkg, apt
40-
```
41-
42-
(You must have ssh access).
43-
44-
### Installing and bootstrapping CFEngine Enterprise Hub
45-
46-
The `install` command can automatically download and install packages as well as bootstrap both hubs and clients.
47-
48-
```
49-
$ cf-remote install --hub 34.247.181.100 --bootstrap 172.31.44.146 --demo
50-
51-
ubuntu@34.247.181.100
52-
OS : ubuntu (debian)
53-
Architecture : x86_64
54-
CFEngine : Not installed
55-
Policy server : None
56-
Binaries : dpkg, apt
57-
58-
Package already downloaded: '/Users/olehermanse/.cfengine/cf-remote/packages/cfengine-nova-hub_3.12.1-1_amd64.deb'
59-
Copying: '/Users/olehermanse/.cfengine/cf-remote/packages/cfengine-nova-hub_3.12.1-1_amd64.deb' to '34.247.181.100'
60-
Installing: 'cfengine-nova-hub_3.12.1-1_amd64.deb' on '34.247.181.100'
61-
CFEngine 3.12.1 was successfully installed on '34.247.181.100'
62-
Bootstrapping: '34.247.181.100' -> '172.31.44.146'
63-
Bootstrap successful: '34.247.181.100' -> '172.31.44.146'
64-
Transferring def.json to hub: '34.247.181.100'
65-
Copying: '/Users/olehermanse/.cfengine/cf-remote/json/def.json' to '34.247.181.100'
66-
Triggering an agent run on: '34.247.181.100'
67-
Disabling password change on hub: '34.247.181.100'
68-
Triggering an agent run on: '34.247.181.100'
69-
Your demo hub is ready: https://34.247.181.100/ (Username: admin, Password: password)
70-
```
71-
72-
Note that this demo setup (`--demo`) is notoriously insecure.
73-
It has default passwords and open access controls.
74-
Don't use it in a production environment.
75-
76-
### Spawning instances in AWS EC2
77-
78-
`cf-remote spawn` can create cloud instances on demand, for example in AWS EC2, but you'll have to add some credentials and settings:
79-
80-
```
81-
$ cf-remote spawn --init-config
82-
Config file /home/olehermanse/.cfengine/cf-remote/cloud_config.json created, please complete the configuration in it.
83-
$ cat /home/olehermanse/.cfengine/cf-remote/cloud_config.json
84-
{
85-
"aws": {
86-
"key": "TBD",
87-
"secret": "TBD",
88-
"key_pair": "TBD",
89-
"security_groups": [
90-
"TBD"
91-
],
92-
"region": "OPTIONAL (DEFAULT: eu-west-1)"
93-
},
94-
"gcp": {
95-
"project_id": "TBD",
96-
"service_account_id": "TBD",
97-
"key_path": "TBD",
98-
"region": "OPTIONAL (DEFAULT: europe-west1-b)"
99-
}
100-
}
101-
```
102-
103-
You can skip the `gcp` values if you will only be using AWS. After filling out those 4, it should just work:
7+
Install using pip:
1048

1059
```
106-
$ cf-remote spawn --count 1 --platform ubuntu-20-04-x64 --role hub --name hub
107-
Spawning VMs....DONE
108-
Waiting for VMs to get IP addresses..........DONE
109-
Details about the spawned VMs can be found in /home/olehermanse/.cfengine/cf-remote/cloud_state.json
10+
pip install cfengine
11011
```
11112

112-
You can now install nightlies, and use the ```--demo``` to make testing easier (**Not** secure for production use).
113-
Referring to the group names set by spawn, makes the commands a lot shorter and easier to script:
13+
## Usage
11414

115-
```
116-
$ cf-remote --version master install --hub hub --bootstrap hub --demo
117-
118-
ubuntu@52.214.209.170
119-
OS : ubuntu (debian)
120-
Architecture : x86_64
121-
CFEngine : Not installed
122-
Policy server : None
123-
Binaries : dpkg, apt
124-
125-
Downloading package: '/home/olehermanse/.cfengine/cf-remote/packages/cfengine-nova-hub_3.18.0a.a24173342~12762.ubuntu18_amd64.deb'
126-
Copying: '/home/olehermanse/.cfengine/cf-remote/packages/cfengine-nova-hub_3.18.0a.a24173342~12762.ubuntu18_amd64.deb' to 'ubuntu@52.214.209.170'
127-
Installing: 'cfengine-nova-hub_3.18.0a.a24173342~12762.ubuntu18_amd64.deb' on 'ubuntu@52.214.209.170'
128-
CFEngine 3.18.0a.a24173342 (Enterprise) was successfully installed on 'ubuntu@52.214.209.170'
129-
Bootstrapping: '52.214.209.170' -> '172.31.5.84'
130-
Bootstrap successful: '52.214.209.170' -> '172.31.5.84'
131-
Transferring def.json to hub: 'ubuntu@52.214.209.170'
132-
Copying: '/home/olehermanse/.cfengine/cf-remote/json/def.json' to 'ubuntu@52.214.209.170'
133-
Triggering an agent run on: '52.214.209.170'
134-
Disabling password change on hub: 'ubuntu@52.214.209.170'
135-
Triggering an agent run on: '52.214.209.170'
136-
Your demo hub is ready: https://52.214.209.170/ (Username: admin, Password: password)
137-
```
138-
139-
Mission portal will be available at that IP, using the username and password from the last log message.
140-
141-
When you are done, you can decommision your spawned instance(s) using:
142-
143-
```
144-
$ cf-remote destroy --all
145-
Destroying all hosts
146-
```
147-
148-
### Deploying a version of masterfiles you're working on locally
149-
150-
The `deploy` command allows you to deploy your local checkout of masterfiles, to test policy while working on it:
151-
152-
```
153-
$ cf-remote deploy --hub hub ~/code/northern.tech/cfengine/masterfiles
154-
155-
ubuntu@18.202.238.128
156-
OS : ubuntu (debian)
157-
Architecture : x86_64
158-
CFEngine : 3.18.0a.a24173342 (Enterprise)
159-
Policy server : None
160-
Binaries : dpkg, apt
15+
To perform an agent run:
16116

162-
Copying: '/home/olehermanse/.cfengine/cf-remote/masterfiles.tgz' to 'ubuntu@18.202.238.128'
163-
Running: 'systemctl stop cfengine3 && rm -rf /var/cfengine/masterfiles && mv masterfiles /var/cfengine/masterfiles && systemctl start cfengine3 && cf-agent -Kf update.cf && cf-agent -K'
164-
$
16517
```
166-
167-
### Specify an SSH key
168-
169-
If you have more than one key in `~/.ssh` you may need to specify which key `cf-remote` is to use.
170-
171-
```
172-
$ export CF_REMOTE_SSH_KEY="~/.ssh/id_rsa.pub"
173-
```
174-
175-
### Working on the local host
176-
177-
`cf-remote` can work on the local host when the target host is `localhost`. In this case, it executes commands locally without connecting over SSH.
178-
179-
```
180-
$ cf-remote info -H localhost
181-
182-
ubuntu@localhost
183-
OS : ubuntu (debian)
184-
Architecture : x86_64
185-
CFEngine : 3.12.1
186-
Policy server : 172.31.42.192
187-
Binaries : dpkg, apt
18+
cfengine run
18819
```
18920

190-
When performing actions locally, `cf-remote` may require your password to run commands with `sudo`:
21+
To get additional help:
19122

19223
```
193-
$ cf-remote install --clients localhost
194-
ubuntu@localhost
195-
OS : debian
196-
Architecture : x86_64
197-
CFEngine : Not installed
198-
Policy server :
199-
Binaries : dpkg, apt
200-
Installing: '/home/ubuntu/.cfengine/cf-remote/packages/cfengine-nova_3.15.3-1.debian10_amd64.deb' on 'localhost'
201-
[sudo] password for ubuntu:
202-
CFEngine 3.15.3 (Enterprise) was successfully installed on 'localhost'
24+
cfengine help
20325
```
20426

205-
## Contribute
206-
207-
Feel free to open pull requests to expand this documentation, add features or fix problems.
208-
You can also pick up an existing task or file an issue in [our bug tracker](https://northerntech.atlassian.net/issues/?filter=10068).
27+
## Supported platforms and versions
20928

210-
## Development
29+
This tool will only support a limited number of platforms, it is not int.
30+
Currently we are targeting:
21131

212-
To install `cf-remote` so that it reflects any changes in this source directory use:
213-
214-
```
215-
$ pip install --editable .
216-
```
32+
- Officially supported versions of macOS, Ubuntu, and Fedora.
33+
- Officially supported versions of Python.
21734

218-
## cloud_data.py tips
35+
It is not intended to be installed on all hosts in your infrastructure.
36+
CFEngine itself supports a wide range of platforms, but this tool is intended to run on your laptop, your workstation, or the hub in your infrastructure, not all the other hosts.
21937

220-
In order to find AWS images for a particular owner to work on cloud_data.py name_pattern list the names for an owner with the following `aws` command:
38+
## Backwards compatibility
22139

222-
aws ec2 describe-images --region us-east-2 --owners 801119661308 --query 'Images[*].[Name]' --output text
40+
This CLI is entirely intended for humans.
41+
If you put it into scripts and automation, expect it to break in the future.
42+
In order to make the user experience better, we might add, change, or remove commands.
43+
We will also be experimenting with different types of interactive prompts and input.

cfengine_cli/commands.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
def run():
1+
def run() -> int:
22
print("RUN")
33
return 0
44

55

6-
def update():
6+
def update() -> int:
77
print("UPDATE")
8+
return 0
89

910

10-
def help():
11+
def help() -> int:
1112
print("HELP")
1213
return 0

cfengine_cli/main.py

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,16 @@
22
import os
33
import sys
44

5-
from cfengine_cli import log
5+
from cf_remote import log
66
from cfengine_cli import version
77
from cfengine_cli import commands
8-
from cf_remote.utils import (
9-
user_error,
10-
)
11-
from cf_remote.utils import cache
8+
from cfengine_cli.utils import UserError
129

1310

1411
def print_version_info():
1512
print("CFEngine CLI version %s" % version.string())
1613

1714

18-
@cache
1915
def _get_arg_parser():
2016
ap = argparse.ArgumentParser(
2117
description="Human-oriented CLI for interacting with CFEngine tools",
@@ -62,29 +58,36 @@ def get_args():
6258
return args
6359

6460

65-
def run_command_with_args(command, _):
61+
def run_command_with_args(command, _) -> int:
6662
if command == "info":
6763
return commands.info()
6864
if command == "run":
6965
return commands.run()
7066
if command == "update":
7167
return commands.update()
72-
user_error("Unknown command: '{}'".format(command))
68+
raise UserError("Unknown command: '{}'".format(command))
7369

7470

7571
def validate_command(_command, _args):
7672
pass
7773

7874

7975
def main():
80-
args = get_args()
81-
if args.log_level:
82-
log.set_level(args.log_level)
83-
validate_command(args.command, args)
84-
85-
exit_code = run_command_with_args(args.command, args)
86-
assert type(exit_code) is int
87-
sys.exit(exit_code)
76+
try:
77+
args = get_args()
78+
if args.log_level:
79+
log.set_level(args.log_level)
80+
validate_command(args.command, args)
81+
82+
exit_code = run_command_with_args(args.command, args)
83+
assert type(exit_code) is int
84+
sys.exit(exit_code)
85+
except AssertionError as e:
86+
print(f"Error: {str(e)} (programmer error, please file a bug)")
87+
sys.exit(-1)
88+
except UserError as e:
89+
print(str(e))
90+
sys.exit(-1)
8891

8992

9093
if __name__ == "__main__":

cfengine_cli/utils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class UserError(Exception):
2+
"""Exception raised when a user has most likely made a mistake"""
3+
4+
def __init__(self, message):
5+
super().__init__(message)
6+
7+
def __str__(self):
8+
return f"Error: {self.message}"

0 commit comments

Comments
 (0)