I’m trying to setup a simple way to define simple deployments. This is in support of my most recent project, and also something that can be used by Dev Dash.
Things can be organized like this:
- A server is one or more server types
- Each server type may have deployed to it one or more applications
- Each application has one or more feature
- Each feature may have one or more web services (and other things, too, but let’s limit it to web services for now)
- Everything needs files (assemblies, etc)
- You can group files into lists and add the lists to other artifacts rather than duplicating files
That’s a simple hierarchy. It gets more complicated, though, because you can add things outside of the hierarchy
- An application has features, but it can also have web services and files assigned to it directly
Dandy. To complicate it more, I want to be able to remove things. For example: Feature A contains 3 web services. But, something above it may want to remove it. IE: Start Feature 3, but exclude one of the web services.
Thus, you end up with a default configuration that you can then add to or remove from.
My first instinct was to start creating some tables to do this, but then I reconsidered and decided to use Model First in EF and let it deal with the tables. Pretty modern of me, right?
It’s a whole bunch of entities with many to many relationships. Ugly. Furthermore, it didn’t work. The model shows the associations between the entities. Behind the scenes, those many-to-many relationships become join tables. If I created this myself in the database, then I would add a column to join tables that would allow me to indicate REMOVE. (IE: one entity inherits a property from another entity, but in this instance I don’t want it). You can’t do that in EF other than to build the join tables as entities, which would result in a nasty model.
Another issue is that I want it to be simple The sql to maintain this (lacking a suitable gui) would be ugly too.
Thus, I began a trial-an-error effort that lasted all week. I started to write something to handle this configuration issue specifically, but quickly realized I can do so more generically.
What I came up with is an on-the-fly model. In a single text file, I identify the object and properties I want, populate the objects, and apply rules. This gives me exactly what I need in a generic way, and I will be able to use it for other things.
That said, it remains immature. One thing that I will have to do (should I pursue this) is to define the model first, then populate it after. As-is, it does whatever you want. By defining the model first, rules and relationships can be defined then enforced.
server test1 servertypes add servertype App Server remove [servertype App Server]/applications[application testapp]/webservices[webservice service1] servertype App Server applications add application testapp add application testapp2 application testapp features add feature test1 webservices add webservice service1 add webservice service3 application testapp2 features add feature test3 add feature test4 webservices add webservice service2 webservice service1 files add string abc.dll add string def.dll add string ghi.dll add string readme.txt webservice service2 files add string a.txt add string b.txt add string c.txt addlist /[filelist somefiles]/files webservice service3 webservice a webservice b feature test1 webservices add webservice a add webservice b feature test3 feature test4 filelist somefiles files add string list1.txt add string list2.txt add string list3.txt add string list4.txt
You can resolve any of the entities that you like, but since I am primarily interested in servers, let’s see what happens when we resolve Server1.
- It is of type app server, so it gets 2 applications, which results in 3 features and 3 web services
- It then removes one of the webservices that it doesn’t want.
Everything is driven by ENTITY TYPE and ENTITY NAME.
Entity Type is defined as the first piece of a non-indented line.
Entity Name is defined after the space following the entity type.
The first level of indent is the property names.
The second level of indent is the commands to populate the property.
Currently, everything is treated as an entity except for string. It is coded for specifically. Other primitives will follow as needed.
All properties are assumed to be collections of entities. That too will mature as needed. IE: set the value of individual properties.
Here’s one of the entity paths:
[servertype App Server]/applications[application testapp]/webservices[webservice service1]
That is on the ServerTypes property of one of the Server entities.
- Finds an entity in the property’s value collection of type servertype and name App Server
- Goes into the applications property
- Finds an entity in the property’s value collection of type application and name test app
- Goes into the webservices property
- Fine an entity in the property’s value collection of type webservice and name service 1
Finally, it’s where it needs to be, and it removes it.
The ADDLIST command is similar.
addlist /[filelist somefiles]/files
Because it begins with the /, it resolves [file list somefiles] rather than look for it wihtin the property collection. It finds it, drills into the files property, and copies all of the values from the files property of the list to the property that contains the command.
There is one more major thing I want to do: have things automatically collapse into each other. For example: This resolves to server/servertype/applications/features/*. I don’t really care about server type. I want to be able to specify that all of the property of server type are rolled up into server, and we never see server type in the output. But, to do that properly, I must define the model ahead of time rather than on-the-fly. (Otherwise, the collapse rules would have to be defined for each instance of the entity… that’s no good.)
This is how I consume the file:
- Now, if I iterate the results and dump them to the console:
servertype App Server – ENTITY
applications – PROPERTY
application testapp – ENTITY
features – PROPERTY
feature test1 – ENTITY
webservices – PROPERTY
webservice a – ENTITY
webservice b – ENTITY
webservices – PROPERTY
webservice service3 – ENTITY
application testapp2 – ENTITY
features – PROPERTY
feature test3 – ENTITY
feature test4 – ENTITY
webservices – PROPERTY
webservice service2 – ENTITY
files – PROPERTY
a.txt – 3 strings
list1.txt – 4 strings added at once from the list
The next step is to conver that to concrete objects. I believe I will easily achieve that via Dynamic