User:Dmacvicar/WebYaST Architecture Proposal

Jump to: navigation, search

WebYaST Architecture Proposal

The following document is a discussion kick-off for WebYaST architecture.

It does not present a definitive solution, but looks at the current architecture and looks why it was done it that way, and tries to evaluate the value of such decisions, presenting alternative designs with the current context and based on the current experience.

A big bold requirement of this proposal is that is not an erase and write again roadmap, but connects the current state of the project to a different state by providing steps that can be done at any speed, reaching a goal and eliminating complexity in any step.

Improving speed and reducing complexity

Current WebYaST offers two servers running on the same machine:

  • UI server
  • REST API server
Old-architecture-proposal.png

The UI server talks to the REST interface only (D2). This design was done for the following reasons:

  • (R1) Allow the creation of tools that consume the API
  • (R2) Keep the client portable across distributions

However, with this design an implicit decision was taken which has little to do with (R1) and (R2)

  • (D3) The REST API is a separate server from the UI server.

Design decision (D3) was done so that a UI server running in one machine could manage a REST server running in another machine. However this flexibility was never really needed, as WebYaST was always intented as 1:1 management, so you could laways go to the machine from the browser instead of having a Browser-Machine1-Machine2 combination.

On the other hand, having a REST API in the same server where the UI server runs, does not prevent the UI server to talk REST to the API present in the same server or a remote API server. However even this design could be avoided, as having the UI server speak REST to the API is creating overhead with no added value than reason (R2), to make the UI server portable. But as most of the UI server is using an ActiveRecord like interface to get the data, we are already abstracted enough to get the data from different sources.

So proposal (P1) is to move all the API to the UI server. A possibility could be to have the same url layout under an /api/v1 namespace.

Another advantage of this is that login and access management is done in one place.

Proposal (P2) is to make the models the UI server use to consume data, to get the data directly from the system, using the methods the current API uses (dbus, YaST) as a first port, but looking into moving into

Proposal (P1) and (P2) together would allow to share the controllers for the UI and the API, returning xml or html depending on the content-type. As a note, Studio uses this design.

Current UI server, as mentioned, uses an ActiveResource like models to access the API. The API server, uses ActiveRecord like models to access the system. So the transition to have one controller using a model to access the system data, and returning html and xml should not be hard to achieve.

Some of these models could be kept as wrappers for dbus/YaST services, while others could plug into the CIM stack by moving ActiveCim forward. The status model could have a model that gets the data directly from the collectd socket, instead of having an intermediate XML conversion.

Also, right now the API has an introspection mechanism. This was done because the following reasons:

  • (R3) Allow different implementations of the same REST api.
  • (R4) Allow the client to find out what services are available.

(R3) never happened, and if it would have been needed, it would be rare that the same machine needs two implementations of the same interface available. Therefore the interface introspection in order to get the URI of the interface does not add any value compared to the client threating the URI as the interface.

(R4) did not add any value as HTTP already offers 404 if a resource is not available and the client could interpret this as a "target machine does not have this service available".

Therefore proposal (P3) is to remove instrospection completely and just use URIs (if the UI server continues talking REST at all, otherwise this would be relevant only for 3rd party tools consuming the API).

This simplification should result in the following benefits:

  • (B1) an architecture simple to understand for developers
  • (B2) less overhead that should bring speed and response times
  • (B3) easier to work with an async user interface without having to resort to jsonp tricks.

The only drawback is to lose the ability to administrate from an UI server an API in another host, which is even now not feasible because we don't care about API version match, and the host selection dialog is hidden.

WebYaST would still offer the API that would allow dashboards to do 1:N management. And by offering alternative implementation of the models used by the controller, still is possible to talk to a remote system if this is actually needed one day.

With all the proposed changes the architecture would look like the following diagram:

WebYaST new architecture proposal 1.gif

The next step would be to define the individual components.

Improving on (R2) would allow to run WebYaST on other distributions, which would help WebYaST relevance. Centering the system access around a dbus service brings the following benefits:

  • Access control via Polkit
  • API reusable from desktop and command line and next "YaST".
  • Proven concept: PackageKit, NetworkManager.

This could lead to the following design:

  • System access spread around some existing (PackageKit, etc) and custom dbus services.
  • The dbus services could access the system directly and with help of augeas.
  • For WebYaST, the dbus calls for stuff like saving could be done with an async delayed job. Adding responsiveness and allowing for "30 seconds" undo, like gmail.
New-architecture-proposal-augeas.png


Security and system access complexity

Once the REST server runs in the same server as the UI server, and both share the same code to get the data, the question is how to get the data, and how to control the access to the data.

Right now the ACL are based on PolicyKit because most actions are going over dbus services. However if the models access the data directly to the system without going over dbus, one may want to think in a ACL model that works no matter where the data comes from.

The current authentication code is custom code and could be ported without big effort to something like Devise making it more common in "Rails". Devise is built on top of Warden, which is based on plain Rack and maintained by a core Rails team member. There are some authorization libraries which work really well with Devise, like CanCan.

Proposal (P4) would be, after doing the same research, use Devise for authentication and CanCan for authorization. This would require to implement a module for devise that replace database_authenticable with a pam_authenticable. The ldap_authenticable module could be used as example. For the authorization side, it would require to implement a CanCan Ability to specify whether the user can do some action on a certain object (in CanCan actions are :symbols and objects are anything).

If the API and the UI are part of the same server, we can use the pure Web and its URL to define what the user has access to. In the same way iChain or AppArmor control whether an user has access to the "resource". The URL _is_ a resource.

What the user is allowed to do with the resource can also be simplified to how the Web works, by controlling whether the user has GET, POST, UPDATE, PUT, DELETE access to the resource.

Other advantages is that if you need mor granular access, you can just move those resources to a more deep URL path. You can define user access matching wildcards, etc. If something like CanCan is used, then the ACLs could also be specified in a more granular way (model classes, etc).

Rails

WebYaST runs on Rails 2.x. In the meantime Rails 3 has been released.

Rails 3 provides a much better controller API when sharing the same data across different response types by using "respond_with".

Rails 3 also allows to activate only the frameworks that are used. WebYaST, if authentication would be implemented properly, should not require ActiveRecord, and under the new version such frameworks can be deactivated.

Proposal (P4) would be to move WebYaST to Rails 3.