[Camps-users] Two tracks of camps system development

Ethan Rowe ethan at endpoint.com
Tue Feb 12 11:47:18 UTC 2008


Jon Jensen wrote:
[snip]
> Ethan and I have several ideas for camps "version 4" that would 
> greatly benefit one of our clients, and which we're discussing 
> implementing for them. I don't want us to do other work on version 4 
> until, hopefully, that client has us do the work. Ethan, would you 
> fill us all in on what you've discussed with them so far?

Happily.

The new design plans address a few critical areas where "version 3" 
falls down:
* extensibility: introduction of support for new services and the ease 
with which those services can be integrated into the system;
* configurability: improve the flexibility of configuration, such that a 
given camp type declares what services exist, their dependency order, 
etc. (this is in contrast to configuration options that give you some 
flexibility in a camp type so long as the application you're 
representing fits neatly into the 
one-database-with-one-appserver-with-one-webserver model);
* host support/awareness: introduce representations of different hosts 
(localhost versus any number of remote hosts) and provide the ability to 
control services on any of those hosts from the primary camp machine;
* unlimited service instances: enable the system to support N instances 
of any given service, within a single host or on different hosts (for 
instance, multiple Postgres clusters for a given camp, so database 
replication concerns can be addressed in the development environment; 
this is also potentially useful for service-oriented architecture, where 
multiple instances of the same app server may be necessary, with 
different configuration for each)

Additional plans that are less fundamental than those listed above:
* command unification: all commands for working with a camp will be 
unified within a master "camp" command, and the interface of each will 
be made consistent;
* administrative commands: introduce new commands so an administrator 
can perform some of the basic setup of a new camp type through 
command-line utilities rather than copying files by hand;
* improved ease of installation: the camp system itself should be 
considerably easier to install on a machine, via at least one of CPAN, 
RPM, etc.;
* programmatic interface: every critical command-line utility will have 
a corresponding method on a master Perl object, which should allow 
easier building of new, higher-level command-line utilities over time, 
and just makes the ways in which camps are used/controlled more flexible

We'll naturally use OOP for this rather than library/exporter modules.  
While keeping the Perl dependencies of the camp system quite light is 
desirable, we'll use Moose as the base object system; while I started 
some prototyping of a simple custom base object, thinking that Moose is 
ultimately more dependent-rich than we would want, Brian Miller 
helpfully pointed out that using Moose would be simpler as a start, and 
if the dependencies were a problem then we could extract Moose out of 
the base object over time.  Jon and I ultimately agreed with that line 
of thinking.

Here's a rough class hierarchy (these package names aren't final by any 
means):
* Camp::Base (bad name) -- base object from which all other objects are 
derived; uses Moose
* Camp::Master -- top level object that coordinates everything
** interacts with the master camp database, which is only used by 
Camp::Master;
*** master camp database: database (Postgres, MySQL, etc.), sqlite, or 
YAML+locking?
** password generation
* Camp::Service -- base class for services, which model pieces of 
software that can be deployed within a camp
** abstract classes of services:
*** databases: Postgres, MySQL, ...
*** vcs: Git, CVS, Subversion, Subversion+SVK, ...
*** static files: non-versioned htdocs, symlinks, ...
*** app servers: Interchange, Rails, ...
*** web servers: Apache, ...
** service attributes:
*** base path
*** port management using "port range" objects
*** socket file paths
* Camp::PortRange --  an object for representing the port needs of a 
given service:
** base port
** number of ports per camp
** initially, port determinations will be algorithmic, based on the base 
port number, the number of ports per camp, and the number of the camp in 
question
* Camp::Host -- object for representing an independent host in which 
services may be deployed
** localhost by default
** other hosts by configuration, accessible via service-specific 
protocol or ssh
* Camp::Resource -- models the actual stuff that goes into a camp, 
combining a service with a host
** resource attributes:
*** name: identifies the resource within the camp type; for simple camp 
types, defaulting to the service name would suffice
*** service: an instance of a Camp::Service subclass
*** host: an instance of Camp::Host (or a subclass), which defaults to 
localhost
** the resource has the opportunity to override the service ports, 
paths, etc. as needed.
* All objects should inherit common logic for configuration file 
parsing, and should know where to find their configuration files
** In reading configuration files, objects will share the following 
behavior:
*** any configuration file token that maps to a known attribute in the 
object in question will be assigned to that attribute, meaning that the 
value is subject to type constraints, validation, etc.
*** for configuration file tokens that don't map to a known attribute in 
the object, a generic attribute of that name will be autovivified, 
without any validation logic whatsoever
*** this allows us to define strict attributes with constraints on them 
while still maintaining the flexibility that comes from letting 
configuration files define arbitrary name/value pairs to be used through 
an application
*** this also means that reading a configuration file means that we're 
potentially extending a module rather than merely putting stuff into an 
object -- this magic will need some planning to make sure namespaces are 
managed effectively and predictably
* All objects will know how to render templates, knowing where the 
templates come from and where they go in the target camp

The configuration scheme will need to be significantly altered to 
accommodate these changes.  So, our thinking here is:
* All configuration files will use YAML; it's simple, flexible, 
powerful, etc.;
* configuration values will be subject to Text::ScriptTemplate 
evaluation for ASP-style embedded calculations; this is more verbose 
than the token-substitution method used in version 3, but it solves the 
0-n problem and ultimately balances an increase in verbosity with an 
enormous leap in flexibility/power;
** within Text::ScriptTemplate evaluations:
*** marshal in a $master object (the Camp::Master instance, through 
which all camp resources can be accessed);
*** marshal in a $self object (which is a reference to the Camp::Host, 
Camp::Service, or Camp::Resource being configured);
** the templates for rendering into a camp will also use 
Text::ScriptTemplate;
* within the "global" camp space, we'll have system-wide configuration 
information for services;
* within the "camp type" space, we'll have configuration information to 
extend/define:
** hosts;
** services;
** resources;
** state the dependency order between resources;
** define the resources that are default for making a new camp, 
stopping/(re)starting a camp, etc.;
* within an individual camp, we'll have configuration information to 
extend/define:
** hosts;
** services;
** resources;
** list the resources used within the camp

The configuration layout would be something like:

<CAMPROOT>/
  services/
    <SERVICE_NAME>/
      config.yml
      etc/ (where templates to be rendered live)
  <TYPE>/
    config.yml (default resources for start/stop/restart/make; specify 
dependency order)
    resources/
      <RESOURCE_NAME>/
        config.yml
        etc/


This design lays the foundation for a very extensible, flexible system 
that could be used in all sorts of development situations, not just its 
initial space of webapps.  The management of hosts and combination of 
service and host into a named resource gives some essential tools for 
representing environments of arbitrary complexity.  The host design can 
presumably be used in the not-too-distant future to enable the use of 
virtual machines, such that making a new camp means auto-instantiating a 
new virtual machine from an existing image.  But we don't need to worry 
about that right now; looking at the body of the email I just wrote, I'd 
say we have enough to worry about for the present.  :)

Thanks.
- Ethan

-- 
Ethan Rowe
End Point Corporation
ethan at endpoint.com




More information about the Camps-users mailing list