dshoreman / servidor Goto Github PK
View Code? Open in Web Editor NEWA modern web application for managing servers
License: GNU Lesser General Public License v2.1
A modern web application for managing servers
License: GNU Lesser General Public License v2.1
Won't be much good if a site is only a name and domain.
Add some dummy UI for adding config blocks to an nginx template.
Should also have spaces for setting other top-level server
rules, along with separate sections for 'custom' blocks - both in the main template section and each individual config block.
There's currently no way of toggling the enabled status of a Site within the UI.
Preferably use a toggle switch for this, to the right of a header. Whether it's added by the actual "Editing Foo" page header or instead in the site card to the left doesn't really matter. The page header will probably be easier though.
Need to have some concept of server templates for use in the Site Editor.
The template itself should be a Blade or Twig view, with placeholders where needed that can be used to "inject" values from the Site config.
Since the placeholders (and thus form fields in the Site Editor) will vary between templates, we'll also need some kind of Class/Interface system to define everything.
Templates should provide:
Example:
class RedirectTemplate implements ServerTemplate
{
protected function template()
{
return 'redirect.blade.php';
}
protected function fields()
{
return [
'destination' => [
'type' => 'text',
'order' => 2,
'rules' => 'required|url',
],
'type' => [
'type' => 'dropdown',
'order' => 1,
'default' => 301,
'options' => [
301 => 'Permanent',
302 => 'Temporary',
307 => 'Permanent (Maintain POST)',
308 => 'Temporary (Maintain POST)',
],
],
];
}
}
When typing in the input on the Sites list, it should filter the list similar to how the System Users/Groups pages function.
It should start off as a Search icon, then once there are no results, change to the Plus icon.
For now, hitting enter should simply create a Site as before. Unless it's an exact match, then we could possibly have it redirect to the edit page for that Site instead.
We can force a site's repo to get pulled again by changing and saving the site config, but this is far from ideal.
Add a button somewhere to request a git pull
for a site. Will probably be better off on more of an "overview" page that summarises the site details rather than cluttering the editor too much.
When you browse to somewhere like /root
which doesn't have read permissions for www-data
, it just throws a 500 and does nothing. If you try to load the page at a path without permission, it'll show a blank file list.
There are probably other ways around it (at least I hope so), but for now we could do with manually parsing output from the ls
command running as sudo. Same goes for opening files, too.
Eventually paths should be checked for permissions before attempting to load anything within them. That'll have to happen when db users are linked to actual system users though - for now we assume superuser status.
Now that there's a file manager, it'd be useful if we had a button directly in the site list (and/or editor) that takes us directly to the current Site's document root in the File Browser.
Instead of the icons defined in code, all are loading as the 'invalid' placeholder.
Project is using SemanticUI for CSS, with scripts from Semantic-UI-Vue (installed via npm) which is probably why it lacks FA.
May just need to add the FA script either to package.json
, or layouts/app
via CDN.
Certain sites, applications or services may be better ran on their own user.
Flags respective to adduser
command, useradd
may differ.
POST /api/users
Request:
username: string|required
group: string|appears_in:groups // -g
groups: list[group] // -G
is_system: // -r / --system
has_homedir: bool|default:true // -m | -M
homedir: path|default:null // -d
### Sample Flow for Creating a User
[Enter a username]
<Which type of user is this?> [normal] [system]
<Can this user login?> [yes] [no]
<Set primary group?> [match username] [select from existing] [custom]
Probably just one input for the site name.
Must create a new site - eventually in the database once API is available - and update the list to include the new entry. Could sort alphabetically or by ID, doesn't really matter. Alpha is probably best.
The domain could be set on the next screen once added, since it's not a certainty that a site will even have a primary domain.
Most of the time it doesn't really matter, but when it comes to finalising a PR ready for merge it can be annoying waiting a minute or two for Travis to do its thing.
Luckily there are some things we can do to improve it:
When running PHPUnit tests in Travis, it spits out an sh: 1: mpstat: not found
error on 3 of the tests.
The tests still pass (maybe that's an issue in itself? Should we be requiring that mpstat
is available in the code using it?) but it makes the output difficult to read, so it'd be nice to get this fixed.
There are currently no tests, but it'd be nice if travis was working for when there are.
Besides, worst case it can probably figure out if something's messed up in composer/node package installation.
The default Semantic UI styles set the body
height to 100%, but the 5 ems of margin-top
applied to the .main
container are pushing the height beyond the viewport.
Either put the margin somewhere else, or calc(100% - 5em)
on the body
to counter it.
Eventually it would be great to have an icon for each of the main file/MIME types to aid in distinguishing between them, but that could be a while off yet.
For now we should have folder icons one colour, with a different colour used for file icons.
If you browse to and open a supported file in the File Manager, it displays fine.
If you then click the <
button to go back to the containing folder and open a different file, you'll occasionally see the first file flash for a moment before it's replaced with the file you intended to see.
This is likely just a case of clearing the file content in the VueX store's state. This could be done either before loading a new file in the viewer, or before leaving the editor route.
CPU and RAM usage are prone to changing frequently, so if the stats bar never updates after loading the page then it won't really be of much use.
Update the axios call such that it re-runs every so often. Some details are likely to change more than others (CPU changing constantly vs disk once in a blue moon) but for now it's probably enough to just ping every 30 seconds or minute.
/sites/{$primary_domain}
or /sites/{$id}
# [My First Site] [status]
Primary Domain: [my-first-site.com]
Server Template: [Laravel ▼]
[PHP ]
[Plain HTML ]
[Redirect ]
[Template Fields]
/public
)temporary
or permanent
)Server templates should be either Blade or Twig templates, probably saved in resources/views/server-tpl
but they might be better in their own folder somewhere.
Validation for the primary domain field seems to run the FQDN check before the required
rule, so when it's left empty the user is prompted that it should be an FQDN rather than it being required.
In addition, the FQDN validation message is not capitalised, so we need to apply a healthy dose of ucfirst()
to it. See below:
If there are errors when you save a site, errors for all fields are correctly displayed including the top "Could not save Site!" alert.
However when you fix the error (for field validation) or resubmit the form (for general errors when saving), the errors don't get cleared even if the latter submission is successful.
We could add frontend validation that deals with all the per-field errors, but we'd still need to deal with the top alert box in case of server errors causing the save to fail. It's probably easier to just reset the errors var in Vue before the ajax call is fired...
While the file viewer works, a plain <pre>
element is a bit... plain. There are easier options for highlighting alone but at some point we'll also need to edit, so we might as well add CodeMirror in the first place to save replacing it later.
It also has the benefit of supporting different colour schemes and editing modes (Vim, emacs and sublime) which would be useful to implement eventually. Until the API supports editing files though, we can keep it read-only.
Add a System dashboard with 'tiles' linking to each page under the System category (currently only users and groups).
System\Dashboard
controller/system
route system.dashboard
SystemDashboard
layouts.app
Eventually it might be better to use the system layout with meaningful dashboard widgets, but for now there's not much to display.
Cloning the source repo works well when you're using master, but if you want to use any other branch you're out of luck.
Add some logic that gets a list of branches on the repo which can be shown in a dropdown to the right of the source repo input. For the list, use git ls-remote <repo> 'refs/heads/*'
to just get branches. Could be nice to get tags too though with 'refs/tags/*'
.
If branch is set, the site update handler should append -b <branch>
to the clone command. We'll probably need to checkout before/after pulling when it already exists too, just in case the branch gets changed.
It'd be awesome if we could have some kind of dropdown menu that lists all the branches for the repo in Site Editor to avoid memorising them or typing them in. This consists of two parts:
We'll need a new endpoint that accepts the value from source_repo
and returns a list of branches. The source repo should be validated using the same rules as when editing a Site.
To get the actual branches we can run git ls-remote --heads <repo_url>
via exec()
. We don't care about the commit SHAs, so everything before and including refs/heads/
can be stripped:
$ git ls-remote --heads https://github.com/dshoreman/servidor.git | sed 's^.*refs/heads/^^'
develop
master
The source_branch
input should be replaced with a SemanticUI Search Selection, which could also allow for setting a specific commit or tag in the future using the search field's value. To get data we'll need to add a listBranches
or similar action to the Site
VueX module, using axios to call the API.
If there are no branches it might be best to revert to a text input in case the repo hasn't been pushed to yet. The store action should be triggered both when the page loads and when the repo URL changes, otherwise we might end up using branches that don't exist on the repo we're saving.
The tl;dr. Each one of these could be a separate PR.
setSiteEditor
mutation to load branches from the API endpointsui-dropdown
componentIf a Site uses a Server Template (not all applications will have a web element) then we need to make sure the site is maintained as an Nginx configuration file in /etc/nginx/sites-available/site-name.conf
.
Updates to the actual config file should preferably only happen when the user specifically triggers it by way of a Save
button or similar.
Add a toggle input below the search field on both the Users and Groups System sections, with a label like 'Include system users' or 'Include system groups'.
Normal users/groups will generally have a UID/GID >= 1000. System U/GIDs will be below 1000.
There's a bit more to it than that, but for now a simple system_user = user.id < 1000
should suffice.
When you type in the name of a user/group that doesn't exist and click Add User/Group, an errors gets thrown in the console about users/groups keys (user.groups
and group.users
).
This in turn prevents creation of the user or group... Not ideal, really.
According to tests/Feature/CreateSiteTest.php, guests can create sites. This is bad. VERY bad.
Test needs to be changed to GuestCanNotCreateSite
with a separate test added to make sure it works for authed users (which can utilise the RequiresAuth
trait added previously).
Naturally, the controller/routes will also need to be updated to fit this behaviour.
Validation in SiteController
defines primary_domain
to be a URL, but really we want a domain/FQDN. Laravel doesn't support that by default, so it's gonna need a custom rule.
Example of a custom rule here: https://stackoverflow.com/questions/47122338/laravel-eloquent-rule-for-domain-name
The primary_domain should be a plain FQDN because it'll be used for various things including Nginx configs where it won't have the https://
or any other protocol/path with it.
Currently if you attempt to view a file you don't have permissions for, or perhaps doesn't exist, it throws a 500.
The 500 is caught fine in the frontend with the error displayed in place of the file contents, but it's not ideal. We need to be checking if the file exists and is readable before we do anything, or at the very least handle the exceptions so that we can return less cryptic error messages.
Currently there's no way to create/set a home directory for a user when you're adding or updating it.
The field should be optional and, to save adding an extra switch, the respective useradd
/usermod
flags to enable/create the home directory should only be passed when the field isn't blank.
775
works great and all, but it would be much easier to understand for a lot of people if it was represented as text, eg:
0600
-> rw-------
0664
-> rw-rw-r--
0775
-> rwxrwxr-x
If it doesn't clutter the UI too much, it could be useful to have a toggle switch somewhere so both representations can be supported.
Instead of displaying the machine name, the StatsBar component is currently displaying 'host' information from the HTTP request. In many cases, this will simply be localhost
, which is less than useful.
Replace request()->getHost()
(added in #10) with something equivalent to the output of hostname
or cat /etc/hostname
on Linux/OSX.
The best solution would be a new GET /api/system/status
API (with tests) which returns a simple key-value array. This could then be fetched to update all information in the StatsBar component, rather than only the hostname.
In the StatsBar
Vue component, 'Carbon' should be replaced with the hostname of the, well, host.
If FQDN is availble, short version is preferred. FQDN could optionally be displayed in a popup.
For now, it would suffice to pass values directly to the Vue component from Laravel in the layouts.app
Blade template.
When the File Manager's current path is several levels deep (eg /var/servidor/.vagrant/machines/default/virtualbox
) it can be a bit tiresome constantly clicking the up button to get back somewhere else.
If we add a computed property that spits out the path as an array (split on /
), it should be pretty easy to link each individual part of the path to that point in the structure.
The hard part would be joining up the half-path for the link and ensuring leading/trailing slashes stay the same.
When editing a site, submission fails when there are errors but the errors don't actually show up in the page so you have to check the network tab in devtools which isn't really ideal.
Need to update the form to show the first error for each input when submission fails. Alternatively could show each input's error combined in one big message
component above the form, but individual errors are preferable.
Currently if you view a file in the file manager, then click the '<' button to return to the containing folder it will update the URL with the path of that folder.
This needs to apply when you're clicking through the file system, including when using the button to go up a level.
Rather than being restricted to a single server template, it should be possible for a user to add as many as needed.
This would allow for defining subdomains in the same place as the primary domain, eg for staging/testing versions.
Like creating users/groups, if you type something in that doesn't exist so that the placeholder is shown, the Clear Search button doesn't work.
The console warns that "Computed propertysearch
was assigned to but has no setter", but who knows why that's gone missing. It used to work just fine...
Occasionally when attempting to reload the page, it'll redirect to the Dashboard which acts as if you're logged in but without displaying any user data.
To replicate, simply destroy and recreate the Vagrant VM (vagrant destroy && vagrant up
). It might be sessions being invalidated, but there are likely other causes too.
Deletion works via the API, but there's no button for it in the frontend.
Add a new Delete
button that triggers a DELETE /api/sites/{site.id}
request through axios, and make sure VueX removes the affected site from the main state.sites
array when complete.
Once you click on a User or Group to open it in the editor, the only way to edit a different one without reloading the page is by first clicking the Cancel button in the editor.
If no changes have been made in the editor, you should be able to click a different User/Group to edit it without closing the existing editor.
When you try to open an image or some other binary file, it dies with an encoding error.
A list of supported MIME types should be added and referenced when loading files. If the file exists and is readable, but its MIME isn't a supported type, we should return a 'Unsupported filetype' error.
While we're just dumping the file contents into a <pre></pre>
block, we can't really display images or anything other than text. There are a few varieties though, so it's worth making sure we have all of 'em. Just a couple examples are:
text/csv
text/css
text/plain
text/markdown
application/x-sh
application/json
application/javascript
text/javascript
Further Reference: Incomplete list of MIME types
The unique:sites,name
rule in Site
validation is preventing updates to a site unless you also change the name.
Need to update this to have the current Site as an exception.
I already have php-cs-fixer configured to run locally when saving files, but if anybody else were to send a PR then it doesn't help us.
Add php-cs-fixer to the Travis CI config to make sure all future code is going to match the rules already defined in .php_cs.dist.
As it says on the tin. If and only if a Site's is_enabled
flag is TRUE
, we should automatically create a symlink to /etc/nginx/sites-available/some-site.conf
in /etc/nginx/sites-enabled/
.
If the Site later gets disabled, the symlink should be removed.
Server should not restart unless manually triggered somewhere, as such an action will affect all Sites on the server. In an ideal world, said action should use systemctl reload ...
rather than restart
as it's slightly less destructive.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.