- 1. Hierarchy
- 2. Cartridge Directory Structure
- 3. Cartridge Metadata
- 4. Managed Files
- 5. Cartridge Locking
- 6. Template Directories for Language Cartridges
- 7. Exposing Services / TCP Endpoints
- 8. Cartridge Scripts
- 9. Custom HTTP Services
- 10. Environment Variables
- 11. Cartridge Events
- 12. Backing Up and Restoring Your Cartridge
- 13. Sample conf.d/openshift.conf.erb
- 14. OpenShift Builds
- 15. OpenShift Upgrades
OpenShift cartridges provide the necessary command and control for the functionality of software that is running users' applications. OpenShift currently has many language cartridges (JBoss EAP, JBoss EWS, PHP, Ruby, Rails, etc.) as well as many DB cartridges (Postgres, Mysql, Mongo, etc.). Before writing your own cartridge, you should search the current list of Red Hat and OpenShift Community provided cartridges.
Cartridge configuration and setup is convention based, with an emphasis on minimizing external dependencies in your cartridge code.
In some cases, multiple cartridges can be co-located or combined in the same gear. To support these scenarios, cartridges enforce a hierarchy that must consist of a single, primary
cartridge and any number of embedded
cartridges. The primary
cartridge controls the build lifecycle, responds to scaling events and is the cartridge responsible for providing some external network accessibility. embedded
cartridges play a supporting role to the primary cartridge, adding capabilities in a more limited fashion. One example of a primary
and embedded
cartridge relationship is between the jenkins
cartridge and the jenkins-client
cartridge. The jenkins
cartridge provides a fully functional Jenkins service that can be accessed via a web browser. The jenkins-client
, on the other hand, needs to be embedded with an existing web application as its role is to simply offload builds to an existing Jenkins service. The client by itself provides no value without being combined with an existing primary cartridge.
This is an example structure to which your cartridge is expected to conform when written to disk. Failure to meet these expectations will cause your cartridge to not function when either installed or used on OpenShift. You may have additional directories or files as required to meet the needs of the software you are packaging and the application developers using your cartridge.
[cartridge name] +- bin (required) (1) | +- setup (optional) (2) | +- install (optional) | +- post_install (optional) | +- teardown (optional) | +- control (required) |- hooks (optional) | +- set-db-connection-info (discretionary) (3) +- versions (discretionary) | +- `software version` | | +- bin | | +- ... | | +- data | | +- template (optional) | | +- .openshift | | | +- ... | | +- ... (directory/file tree) | | +- template.git (discretionary) | | +- ... (git bare repo) | +- ... +- env (required) | +- *.erb +- template (optional) | +- ... (directory/file tree) + template.git (discretionary) + +- ... (bare git repository) +- usr (optional) | +- ... +- metadata (required) | +- manifest.yml (required) | +- managed_files.yml (optional) +- conf.d (discretionary) | +- openshift.conf.erb +- conf (discretionary) | +- magic
-
required
items must exist for minimal OpenShift support of your cartridge -
optional
exist to support additional functionality -
discretionary
should be considered best practices for your cartridge and work. E.g.,conf.d
is the usual name for where a web framework would install itshttpd
configuration.
To support multiple software versions within one cartridge, you may create symlinks between the bin/control
and the versions/{software version}/bin/control
file. Or, you may choose to
use the bin/control
file as a shim to call the correct versioned control
file.
When creating an instance of your cartridge for use by a gear, OpenShift will copy the files, links, and directories from the cartridge library with the exclusion of the usr
directory. The usr
directory will be symlinked into the gear’s cartridge instance. This allows for the sharing of libraries and other data across all cartridge instances.
Later (see Cartridge Locking) we’ll describe how, as the cartridge author, you can customize a cartridge instance.
The manifest.yml
file is used by OpenShift to determine what features your cartridge requires and in turn publishes. OpenShift also uses fields in the manifest.yml
to determine what data to present to the cartridge user about your cartridge.
An example manifest.yml
file:
Name: PHP
Cartridge-Short-Name: PHP
Cartridge-Version: '1.0.1'
Compatible-Versions:
- '1.0.1'
Cartridge-Vendor: redhat
Display-Name: PHP 5.3
Description: "PHP is a general-purpose server-side scripting language..."
Version: '5.3'
Versions:
- '5.3'
License: "The PHP License, version 3.0"
License-Url: http://www.php.net/license/3_0.txt
Vendor: PHP Group
Categories:
- service
- php
- web_framework
Website: http://www.php.net
Help-Topics:
"Developer Center": https://www.openshift.com/developers
Cart-Data:
- Key: OPENSHIFT_...
Type: environment
Description: "How environment variable should be used"
Provides:
- php-5.3
- "php"
Publishes:
get-php-ini:
Type: "FILESYSTEM:php-ini"
publish-http-url:
Type: "NET_TCP:httpd-proxy-info"
publish-gear-endpoint:
Type: "NET_TCP:gear-endpoint-info"
Subscribes:
set-db-connection-info:
Type: "NET_TCP:db:connection-info"
Required: false
set-nosql-db-connection-info:
Type: "NET_TCP:nosqldb:connection-info"
Required: false
set-mysql-connection-info:
Type: "NET_TCP:db:mysql"
Required : false
set-postgres-connection-info:
Type: "NET_TCP:db:postgres"
Required : false
set-doc-url:
Type: "STRING:urlpath"
Required : false
Scaling:
Min: 1
Max: -1
Group-Overrides:
- components:
- php-5.3
- web_proxy
Endpoints:
- Private-IP-Name: IP1
Private-Port-Name: HTTP_PORT
Private-Port: 8080
Public-Port-Name: PROXY_HTTP_PORT
Mappings:
- Frontend: "/front"
Backend: "/back"
Additional-Control-Actions:
- threaddump
OpenShift creates a number of environment variables for you when installing your cartridge. This shortened name is used when creating those variables. For example, using the example manifest, the following environment variables would be created:
OPENSHIFT_PHP_DIR OPENSHIFT_PHP_IP OPENSHIFT_PHP_PORT OPENSHIFT_PHP_PROXY_PORT
The Cartridge-Version
element is a version number identifying a release of your cartridge to OpenShift. The value follows the format:
<number>[.<number>[.<number>[...]]]
When you publish new versions of your cartridge to OpenShift, this number will be used to determine what is necessary to upgrade the application developer’s application. YAML will assume number.number is a float; be sure to enclose it in quotes so it is read as a string.
Compatible-Versions
is a list of past cartridge versions that are compatible with this version. To be compatible with a previous version, the code changes you made in this version do not require the cartridge to be restarted or the application developer’s application to be restarted.
Compatible-Versions: ['1.0.1']
By not requiring a restart, you improve the application user’s experience since no downtime will be incurred from your changes. If the cartridge’s current version is not in the list when upgraded, the cartridge will be stopped, the new code will be installed, setup
will be run, and the cartridge started.
Today this is a simple list and string matching is used to determine compatible versions. If this list proves to be unmanageable, future versions of OpenShift may implement maven dependency range style checking.
The Cartridge-Vendor
element is used to differentiate cartridges when installed in the system. As an individual, you should use the same unique value for all your cartridges to identify yourself; otherwise, use your company name.
The Version
element is the default or only version of the software packaged by this cartridge.
Version: '5.3'
Versions
is the list of the versions of the software packaged by this cartridge.
Versions: ['5.3']
Categories
represent a list of classifications for a given cartridge. Categories are broken into two distinct groups:
-
system
categories have special meaning to the platform and influence system behavior. -
descriptive
categories are arbitrary classifications used to improve searching for cartridges in the web console and client tools.
system
categories consist of the following reserved terms:
-
web_framework
-
web_proxy
-
service
-
plugin
-
embedded
-
domain_scope
The web_framework
category is used to describe a primary cartridge that accepts inbound HTTP and HTTPS as well as WebSocket requests. An application can have a single cartridge with the web_framework
category. Lastly, when using a web_framework
category, SSL termination occurs at the platform layer, before the cartridge interaction takes place and the original inbound protocol is passed using the X-Forwarded-Proto
header to the cartridge.
The web_proxy
category is used to describe a cartridge that is responsible for routing web traffic to the application’s gears. If a scalable application is created with a cartridge that has the web_framework
category, a web_proxy
cartridge is also added to it to enable auto-scaling. Subsequently, whenever the web_framework
cartridge needs to scale beyond a single gear, the web_proxy
cartridge will automatically route to the end point described by the Public-Port-Name
with a value of PROXY_PORT
. The web_proxy
will also be automatically updated with routing rules to address the new gears over HTTP as they are added. An application can have a single cartridge with the web_proxy
category.
The service
category is used to describe a primary cartridge that is not necessarily HTTP-based. This means that the cartridge can scale independently but is not necessarily addressable outside of the platform. Because of this, when creating an application in OpenShift, there is a restriction that at least one web_framework
cartridge be present in the application so that the DNS registration for the application contains at least one well known addressable endpoint for the application over HTTP. However, in many cases, an application might need to consist of a web_framework
cartridge and other service
cartridges such as MySQL. By using the category of service
for a cartridge like MySQL, it will install the cartridge on separate gears from the web_framework
cartridge and allow it to scale independently as well.
The embedded
category is used to describe whether a cartridge can be co-located with a primary
cartridge. It is relevant only in case of non-scalable applications. This category allows the cartridge to always be co-located or installed with any other primary
cartridge. An example of this would be the Jenkins client cartridge which can always be combined with any web application cartridge to offload the builds to a Jenkins service.
The plugin
category is the equivalent of the embedded
category for scalable applications. A plugin cartridge is designed to be co-located with another cartridge in a scalable application. It relies upon Group-Overrides
being defined to determine which cartridge it should co-locate with. An example of this is the cron cartridge that is a plugin and specifies through Group-Overrides
that it needs to co-locate with the web_framework
cartridge.
The domain_scope
category describes a cartridge that can only have a single instance within the domain. For example, the jenkins server cartridge has the domain_scope
category to ensure that there is a single jenkins server application within the entire domain. All other applications embed
the jenkins client cartridge to enable builds that are handled by the jenkins server.
The descriptive
categories are primarily used in the OpenShift web console and the rhc
client tools to improve the user experience. In the web console, descriptive
categories show up as tags which allow users to search and quickly filter the available cartridges. When using the client tools, these categories are used to apply matching logic on cartridge related operations. For example, if a user ran:
rhc add-cartridge php
The descriptive
categories will be searched in addition to the names of the cartridges.
Group-Overrides
is applicable in case of scalable applications. By default, for scalable applications, each cartridge resides on its own gears within its own group instance. However, sometimes it is required/preferred to have two cartridges be located together on the same set of gears. Group-Overrides
lets you do this. For example, if you create a cron
cartridge, and you want it to colocate with the web_framework
cartridge, you can specify:
Group-Overrides: - components: - web_framework - cron
Similarly, if you would like the web_framework cartridge to be located along with the web_proxy
cartridge, then you can specify:
Group-Overrides: - components: - web_proxy - web_framework
This section defines the scaling parameters for a cartridge and is applicable when the cartridge is added to a scalable application. The Min
and Max
parameters define the scaling limits for the cartridge. Setting both the Min
and Max
equal to 1 indicates that the cartridge cannot scale. On the other hand, if Max
is specified as -1, then there is no maximum scaling limit and the cartridge can scale up as long as the user’s gear limit is not exceeded. The scaling limits are enforced during auto-scaling as well as when setting the cartridge scaling limits manually.
When using Group-Overrides
to co-locate two or more cartridges that can all scale, it is important to ensure that their scaling limits match. There are occasions, however, when this is not desirable, such as in the case of a web_proxy
that is co-located with the web_framework
. In this case it doesn’t make sense to have the web_proxy
cartridge be present on every gear where the web_framework
gear is located. The Multiplier
parameter enables this by allowing the cartridge to be placed on fewer gears within the group instance. For example, if the Multiplier
is set to 3, then every third gear within the group instance will have the cartridge installed. Similarly, if the Multiplier
is set to 1, then all gears within the group instance will have the cartridge installed on them.
Provides
is a list of features or functionalities that the cartridge provides to the application. For example, the php-5.3 cartridge provides php-5.3 as well as, more generically, php.
Provides: - php-5.3 - php
Requires
is a list of features or functionalities that this cartridge depends upon for its operation. These dependencies would be matched against other available cartridges to find the ones that provide them. For example, a framework cartridge like Rails could require a language/runtime cartridge like Ruby. In this case, if an application is being created with the Rails cartridge, based on the Requires
specification, a cartridge that provides Ruby would be automatically added to the application.
The functionality specified in the Requires
section must identify a single cartridge. In case multiple cartridges are matched, then the cartridge cannot be added and an error is raised to the user.
Source-Url
is used when you self-distribute your cartridges. They are downloaded at the time the application is created.
Scheme | Method | Expected Inputs |
---|---|---|
https |
GET |
extensions zip, tar, tag.gz, tgz |
http |
GET |
extensions zip, tar, tag.gz, tgz |
file |
file copy |
cartridge directory tree expected |
All Git schemes are supported. The cartridge source will be cloned from the given repository.
Source-Url: https://github.com/example/killer-cartridge.git Source-Url: git://github.com/chrisk/fakeweb.git Source-Url: https://www.example.com/killer-cartridge.zip Source-Url: https://github.com/example/killer-cartridge/archive/master.zip
If Source-Md5
is provided and a non-Git scheme is used for downloading your cartridge, OpenShift will verify the downloaded file against this MD5 digest.
Source-Md5: 835ed97b00a61f0dae2e2b7a75c672db
The Additional-Control-Actions
element is a list of optional actions supported by your cartridge. threaddump
is an example of one such action. OpenShift will only call optional actions if they are included in this element. Supported optional actions:
threaddump
The metadata/managed_files.yml
file provides an array of files or strings that are managed or used during different stages of your cartridge lifecycle. The keys for the entries (such as locked_files
) can be specified as either strings or Ruby symbols. For example:
locked_files:
- env/
- ~/.foorc
snapshot_exclusions:
- mydir/*
restore_transforms:
- s|${OPENSHIFT_GEAR_NAME}/data|app-root/data|
processed_templates:
- '**/*.erb'
setup_rewritten:
- conf/*
Most entries will use file patterns. These patterns are treated like Shell globs. Any entry that contains one or more *
will be processed by Dir.glob
(with the File::FNM_DOTMATCH
flag). Any entry that ends in a /
is treated as a directory; otherwise it will be treated as a single file.
Any lines starting with ~/
will be anchored at the gear directory; otherwise, they will be anchored to your cartridge directory.
Some entries allow for string values in the arrays. In this case, the values will be directly returned without any modification.
Currently, the following entries are supported:
Entry | Type | Usage |
---|---|---|
locked_files |
File Pattern |
|
snapshot_exclusions |
File Pattern |
|
restore_transforms |
Strings |
|
setup_rewritten |
File Pattern |
|
processed_templates |
File Pattern |
Cartridge instances within a gear will be either locked
or unlocked
at any given time. Locking a cartridge allows the cartridge scripts to have additional access to the gear’s files and directories. Other scripts and hooks written by the application developer will not be able to override decisions you make as the cartridge author.
The lock state is controlled by OpenShift. Cartridges are locked and unlocked at various points in the cartridge lifecycle.
If you fail to provide a locked_files
entry in metadata/managed_files.yml
or the file is empty, your cartridge will remain always unlocked. For very simple cartridges, this may be
sufficient.
Warning
|
Cartridge file locking is not intended to be a security measure. It is a mechanism to help prevent application developers from inadvertently breaking their application by modifying files reserved for use by you, the cartridge author. |
The metadata/managed_files.yml
locked_files
entry lists the files and directories, one per line, that will be provided to the cartridge author with read/write access while the cartridge is unlocked, but only read access to the application developer while the cartridge is locked.
Any non-existent files that are included in the list will be created before your setup
script is called. Any missing parent directories will be created as needed. The list is anchored at the cartridge’s directory. An entry ending in slash is processed as a directory. Entries ending in asterisk are a list of files. Entries ending in any other character are considered files. OpenShift will not attempt to change files to directories or vice versa, and your cartridge may fail to operate if files are miscategorized and you depend on OpenShift to create them.
Here is a locked_files
entry for a PHP cartridge:
locked_files:
- ~/.pearrc (1)
- bin/ (2)
- conf/* (3)
-
The file
~/.pearrc
will be created, if it does not exist, and be made editable by you. -
The directory
php/bin
is locked but not the files it contains. While you can add files, both you and the application developer can edit any files contained. -
The files in
php/conf
are locked but the directory itself is not, so you or the application developer can add files, but only you can edit them.
Directories like ~/.node-gyp
and ~/.npm
in nodejs are NOT
candidates to be created in this manner as they require the application
developer to have read and write access while the application is
deploying and running. These directories would need to be created by the
nodejs setup
or install
scripts.
The following list is reserved by OpenShift in the gear’s home directory:
-
~/.ssh
-
~/.sandbox
-
~/.tmp
-
~/.env
-
any non-hidden directory or file
You may create any hidden file or directory (one that starts with a period) not in the reserved list in the gear’s home directory while the cartridge is unlocked.
The template
or template.git
directory should provide an minimal example of an application written in the language/framework your cartridge is packaging. Your application should welcome the application developer to your cartridge and let them see that your cartridge has indeed been installed and operates. If you provide a template
directory, OpenShift will transform it into a bare git repository for use by the application developer. If you provide a template.git
directory, OpenShift will copy the directory for use by the application
developer.
Your setup
and install
scripts should assume that template
directories may be converted to template.git
during the packaging of your cartridge for use by OpenShift. The PaaS operator may choose to convert all template
directories to bare git repositories template.git
to obtain the performance gain when adding your cartridge to a gear. One good workflow point to make this change is when your cartridge is packaged into an RPM.
A ruby 1.8
with Passenger
support would have a public
sub-directory and a config.ru
file to define the web application.
+- template | +- config.ru | +- public | | +- .gitignore | .openshift | +- markers | |- ...
Note
|
A .gitignore file should be placed in empty directories to ensure they survive when the file tree is loaded into a git repository.
|
The sub-directory .openshift/markers
may contain example files for the application developer. These files denote behavior you are expected to honor in your cartridge’s lifecycle. Current examples from a Ruby 1.8 cartridge include:
Marker | Action |
---|---|
force_clean_build |
Remove and previously built artifacts (gems/maven artifacts/etc) before starting the next build. Note: Turning off auto deploy on your application and specify force_clean_build on a per deploy basis is generally preferred over this option. |
hot_deploy |
Perform the minimal restart to pick up code changes. Skips any non required packaging steps such as bundle installing gems. Note: Turning off auto deploy on your application and specify hot_deploy on a per deploy basis is generally preferred over this option. |
disable_auto_scaling |
Will prevent scalable applications from scaling up or down according to application load. |
You may add additional markers to allow an application developer to control aspects of your cartridge.
The sub-directory .openshift/action_hooks
will contain code the application developer wishes to be run during lifecycle changes. Examples would be:
pre_start_`cartridge name` post_start_`cartridge name` pre_stop_`cartridge name` ...
As a cartridge author you do not need to execute the default action_hooks
. OpenShift will call them during lifecycle changes based on the actions given to the control
script. If you wish to add additional hooks, you are expected to document them and you will need to run them explicitly in your control
script.
Most cartridges provide a service by binding to one or many ports. Cartridges must explicitly declare which ports they will bind to, and provide meaningful variable names to describe the following:
-
Any IP addresses necessary for binding
-
The gear-local ports to which the cartridge services will bind
-
(Optional) Publicly proxied ports which expose gear-local ports for use by the application’s users or intra-gear. These endpoint ports are only created when the application is scalable.
In addition to IP and port definitions, Endpoints are where front-end httpd mappings for your cartridge are declared to route traffic from the outside world to your cartridge’s services.
These declarations represent Endpoints, and are defined in the cartridge manifest.yml
in the Endpoints
section using the following format:
Endpoints:
- Private-IP-Name: <name of IP variable>
Private-Port-Name: <name of port variable>
Private-Port: <port number>
Public-Port-Name: <name of public port variable>
Mappings:
- Frontend: "<frontend path>"
Backend: "<backend path>"
Options: { ... }
- <...>
- <...>
During cartridge installation within a gear, IP addresses will be automatically allocated and assigned to each distinct IP variable name, with the guarantee that the specified port will be bindable on the allocated address.
If an endpoint specifies a public port variable, a public port proxy mapping will be created using a random external port accessible via the gear’s DNS entry.
Each portion of the Endpoint definition becomes available via environment variables located within the gear and accessible to cartridge scripts and application code. The names of these variables are prefixed with OpenShift namespacing information in the follow the format:
OPENSHIFT_{Cartridge-Short-Name}_{name of IP variable} (1) OPENSHIFT_{Cartridge-Short-Name}_{name of port variable} (2) OPENSHIFT_{Cartridge-Short-Name}_{name of public port variable} (3)
-
Assigned internal IP
-
Endpoint-specified port
-
Assigned external port
Cartridge-Short-Name
is the Cartridge-Short-Name element from the cartridge manifest file.
If an Endpoint specifies a Mappings
section, each mapping entry will be used to create a frontend httpd route to your cartridge using the provided options. The Frontend
key represents a frontend path element to be connected to a backend URI specified by the Backend
key. The optional Options
hash for a mapping allows the route to be configured in a variety of ways:
-
websocket
- Enable web sockets on a particular path -
gone
- Mark the path as gone (uri is ignored) -
forbidden
- Mark the path as forbidden (uri is ignored) -
noproxy
- Mark the path as not proxied (uri is ignored) -
redirect
- Use redirection to uri instead of proxy (uri must be a path) -
file
- Ignore request and load file path contained in uri (must be path) -
tohttps
- Redirect request to https and use the path contained in the uri (must be path)
While more than one option is allowed, the above options conflict with each other.
Given a cartridge named CustomCart
and the following entry in manifest.yml
:
Name: CustomCart
Cartridge-Short-Name: CUSTOMCART
# ...
Endpoints:
- Private-IP-Name: HTTP_IP
Private-Port-Name: WEB_PORT
Private-Port: 8080
Public-Port-Name: WEB_PROXY_PORT
Mappings:
- Frontend: "/web_front"
Backend: "/web_back"
- Frontend: "/socket_front"
Backend: "/socket_back"
Options: { "websocket": true }
- Private-IP-Name: HTTP_IP
Private-Port-Name: ADMIN_PORT
Private-Port: 9000
Public-Port-Name: ADMIN_PROXY_PORT
Mappings:
- Frontend: "/admin_front"
- Backend: "/admin_back"
- Private-IP-Name: INTERNAL_SERVICE_IP
Private-Port-Name: 5544
Public-Port-Name: INTERNAL_SERVICE_PORT
The following environment variables will be generated:
# Internal IP/port allocations OPENSHIFT_CUSTOMCART_HTTP_IP=<assigned internal IP 1> OPENSHIFT_CUSTOMCART_WEB_PORT=8080 OPENSHIFT_CUSTOMCART_ADMIN_PORT=9000 OPENSHIFT_CUSTOMCART_INTERNAL_SERVICE_IP=<assigned internal IP 2> OPENSHIFT_CUSTOMCART_INTERNAL_SERVICE_PORT=5544 # Public proxy port mappings OPENSHIFT_CUSTOMCART_WEB_PROXY_PORT=<assigned public port 1> OPENSHIFT_CUSTOMCART_ADMIN_PROXY_PORT=<assigned public port 2>
In the above example, the public proxy port mappings are as follows:
<assigned external IP>:<assigned public port 1> => OPENSHIFT_CUSTOMCART_HTTP_IP:OPENSHIFT_CUSTOMCART_WEB_PORT <assigned external IP>:<assigned public port 2> => OPENSHIFT_CUSTOMCART_HTTP_IP:OPENSHIFT_CUSTOMCART_ADMIN_PORT
And finally, the following frontend httpd routes will be created:
http://<app dns>/web_front => http://OPENSHIFT_CUSTOMCART_HTTP_IP:8080/web_back http://<app dns>/socket_front => http://OPENSHIFT_CUSTOMCART_HTTP_IP:8080/socket_back http://<app dns>/admin_front => http://OPENSHIFT_CUSTOMCART_HTTP_IP:9000/admin_back
How you implement the cartridge scripts in the bin
directory is up to you as the author. For easily configured software where your cartridge is just installing one version, these scripts may include all the necessary code. For complex configurations or multi-version support, you may choose to write these scripts as shim code to setup the necessary environment before calling additional scripts you write. Or, you may choose to create symlinks from these names to a name of your choosing. Your API is the scripts and their associated actions.
The scripts will be run directly from the home directory of the cartridge. They need to have the executable bit turned on, and they should have UNIX-friendly line endings (\n
), not DOS ones (\r\n
).
To ensure this, consider setting the following git
options (just once) so that the files have correct line endings in the git repository:
git config --global core.autocrlf input # use `true` on Windows git config --global core.safecrlf true
To ensure that the executable bit is on, on UNIX-like systems, run:
chmod +x bin/*
Note
|
On Windows, you can achieve this by running git update-index --chmod=+x bin/* in the cartridge directory.
|
A cartridge must implement the following script:
Script Name | Usage |
---|---|
control |
Command cartridge to report or change state |
A cartridge may implement the following scripts:
Script Name | Usage |
---|---|
setup |
Prepare this instance of cartridge to be operational for the initial install and each incompatible upgrade |
install |
Prepare this instance of cartridge to be operational for the initial install |
post_install |
An opportunity for configuration after the cartridge has been started for the initial install |
teardown |
Prepare this instance of cartridge to be removed |
OpenShift follows the convention that your scripts should return zero for success and non-zero for failure. Additionally, OpenShift supports special handling of the following non-zero exit codes:
Exit Code | Usage |
---|---|
127 |
TODO |
131 |
TODO |
These exit status codes will allow OpenShift to refine its behavior when returning HTTP status codes for the REST API, whether an internal operation can continue or should aborted, etc. Should your script return a value not included in this table, OpenShift will assume the problem is fatal to your cartridge.
The initial install process for a cartridge is as follows:
-
The new cartridge is overlaid in the gear.
-
The cartridge Environment Variables are populated.
-
The cartridge directory is secured.
-
The private Endpoints are created.
-
The cartridge directory is unlocked.
-
If the cartridge provides a
setup
script, that script is executed. -
The erb templates for the cartridge are processed.
-
If the cartridge provides an
install
script, that script is executed. -
The gear git repository is populated.
-
The cartridge directory is locked.
-
The public Endpoints are created.
-
The
start
script is run. -
The frontend is connected.
-
If the cartridge provides a
post_install
script, that script is executed. -
The cartridge is started.
In order to provide flexible configuration and environment variables, you may provide some values as ERB templates.
Your templates will be rendered at safe_level 2
. and are processed in 2 passes.
-
The first pass processes any entries in your
env
directory. This pass happens beforebin/setup
is called and is mandatory. -
The second pass processes any entries specified in the
processed_templates
entry ofmetadata/managed_files.yml
. This pass happens afterbin/setup
but beforebin/install
. This allowsbin/setup
to create or modify ERB templates if needed. It also allows forbin/install
to use these values or processed files.
-
Given
env/OPENSHIFT_MONGODB_DB_LOG_DIR.erb
containing:
<%= ENV['OPENSHIFT_HOMEDIR'] + "/mongodb/log/" %>
becomes env/OPENSHIFT_MONGODB_DB_LOG_DIR
containing:
/var/lib/openshift/aa9e0f66e6451791f86904eef0939e/mongodb/log/
-
Given
conf/php.ini.erb
containing:
upload_tmp_dir = "<%= ENV['OPENSHIFT_HOMEDIR'] %>php/tmp/" session.save_path = "<%= ENV['OPENSHIFT_HOMEDIR'] %>php/sessions/"
becomes conf/php.ini
containing:
upload_tmp_dir = "/var/lib/openshift/aa9e0f66e6451791f86904eef0939e/php/tmp/" session.save_path = "/var/lib/openshift/aa9e0f66e6451791f86904eef0939e/php/sessions/"
Other candidates for templates are httpd configuration files for
includes
, configuring databases to store persistent data in
OPENSHIFT_DATA_DIR
, and setting the application name in the pom.xml
file.
- Synopsis
-
setup [--version <version>]
- Options
-
--version <version>
: Selects which version of cartridge to install. If no version is provided, the version denoted by theVersion
element frommanifest.yml
will be installed. - Description
-
The
setup
script is responsible for creating and/or configuring the files that were copied from the cartridge repository into the gear’s directory. Setup must also be reentrant and will be called on every incompatible upgrade. Any logic you want to occur only once should be added toinstall
.Any files created during
setup
should be added tosetup_rewritten
section ofmetadata/managed_files.yml
. These files will be deleted prior tosetup
being run during upgrades.If you have used ERB templates for software configuration those files will be processed for environment variable substitution after
setup
is run. - Lock Context
-
unlocked
- Synopsis
-
install [--version <version>]
- Options
-
--version <version>
: Selects which version of cartridge to install. If no version is provided, the version denoted by theVersion
element frommanifest.yml
will be installed. - Description
-
The
install
script is responsible for creating and/or configuring the files that were copied from the cartridge repository into the gear’s directory.install
will only be called on the initial install of a cartridge.-
Any one-time operations, such as generating passwords, creating ssh keys, or adding environment variables, should occur in
install
. -
Additionally, any client results/messages should also be reported in
install
rather thansetup
. -
install
may substitute a version dependent of thetemplate
ortemplate.git
directories.
-
- Lock Context
-
unlocked
- Synopsis
-
post_install [--version <version>]
- Options
-
--version <version>
: Selects which version of cartridge to install. If no version is provided, the version denoted by theVersion
element frommanifest.yml
will be installed. - Description
-
The
post_install
script is an opportunity to configure your cartridge after the cartridge has been started and is only called for the initial install of the cartridge. - Lock Context
-
locked
- Synopsis
-
teardown
- Options
-
None
- Description
-
The
teardown
script prepares the gear for the cartridge to be removed. This script will not be called when the gear is destroyed. Theteardown
script is only run when a cartridge is to be removed from the gear. The gear is expected to continue to operate minus the functionality of your cartridge cartridge. - Lock Context
-
unlocked
- Synopsis
-
control <action>
- Options
-
action
: which operation the cartridge should perform. - Description
-
The
control
script allows OpenShift or user to control the state of the cartridge. - Lock Context
-
locked
Here is the list of operations your cartridge may be called to perform:
Operation | Behavior |
---|---|
update-configuration, pre-build, build, deploy, or post-deploy |
described in the OpenShift Builds section |
start |
Start the software your cartridge controls |
stop |
Stop the software your cartridge controls |
status |
Return an 0 exit status if your cartridge code is running |
reload |
Your cartridge and the packaged software needs to re-read their configuration information (this operation will only be called if your cartridge is running) |
restart |
Stop current process and start a new one for the code your cartridge packages |
threaddump |
If applicable, your cartridge should signal the packaged software to perform a thread dump |
tidy |
All unused resources should be released (it is at your discretion to determine what should be done; be frugal as on some systems resources may be very limited) |
pre-snapshot |
Prepare the cartridge for a snapshot, e.g. dump database to flat file |
post-snapshot |
Clean up the cartridge after snapshot, e.g. remove database dump file |
pre-restore |
Prepare the cartridge for restore |
post-restore |
Clean up the cartridge after being restored, load database with data from flat file |
Some possible tidy
behaviors:
-
rm $OPENSHIFT_{Cartridge-Short_Name}_DIR/logs/log.[0-9]
-
cd $OPENSHIFT_REPO_DIR ; mvn clean
OpenShift has the following default tidy
behaviors:
-
the Git repository will be garbage collected
-
all files will be removed from the
/tmp
directory
For a number of reasons, the application developer will want to be able to query whether the software your cartridge packages is running and behaving as expected. A 0
exit status implies that the software is running correctly.
You may direct information to the application developer by writing to stdout. Errors may be return on stderr with a non-zero exit status.
OpenShift maintains the expected state of the gear/application in ~/app-root/runtime/.state
. You may not use this to determine the status of the software you are packaging. That software may have crashed so you would be returning an invalid status if you used this file’s value. Future versions of OpenShift may combine the results from the status
action and the value of the .state
file to automatically restart failed applications. For completeness, see the following .state
values:
Value | Meaning |
---|---|
building |
Application is currently being built |
deploying |
Application is currently being deployed |
idle |
Application has been shutdown because of no activity |
new |
Gear has been created, but no application has been installed |
started |
Application has been commanded to start |
stopped |
Application has been commanded to stop |
Your cartridge may provide one or more services that are consumed by multiple gears in one application. OpenShift provides the orchestration necessary for you to publish this service or services. Each message is written to stdout, one message per line.
-
ENV_VAR_ADD: <variable name>=<value>
-
CART_DATA: <variable name>=<value>
-
CART_PROPERTIES: <key>=<value>
-
APP_INFO: <value>
Your cartridge may expose services using the application’s URL by providing one or more snippets of Apache configuration code using ERB templates in the httpd.d
directory. The httpd.d
directory and its contents are optional. After OpenShift has run your setup
script, it will render each ERB template and write the contents of the node’s httpd configuration.
An example of mongodb.conf.erb
:
Alias /health <%= ENV['OPENSHIFT_HOMEDIR'] + "/mongodb/httpd.d/health.html" %> Alias / <%= ENV['OPENSHIFT_HOMEDIR'] + "/mongodb/httpd.d/index.html" %>
Environment variables are used to communicate information between this cartridge and others, as well as to OpenShift. The cartridge controlled variables are stored in the env
directory and will be loaded after system-provided environment variables but before your code is called. OpenShift-provided environment variables will be loaded and available to be used for all cartridge entry points.
You cannot override system provided variables by creating new copies in your cartridge env
directory. If you attempt to do so, when an application developer attempts to instantiate your cartridge the system will raise an exception and refuse to do so.
With the exception of OPENSHIFT_SECRET_TOKEN
, these variables may not be overridden using rhc env-set
.
Name | Value |
---|---|
HOME |
Alias for |
HISTFILE |
Bash history file |
OPENSHIFT_APP_DNS |
The application’s fully qualified domain name that your cartridge is a part of |
OPENSHIFT_APP_NAME |
The validated user assigned name for the application (black list is system dependent) |
OPENSHIFT_APP_UUID |
OpenShift-assigned UUID for the application |
OPENSHIFT_DATA_DIR |
The directory where your cartridge may store data |
OPENSHIFT_GEAR_DNS |
The gear’s fully qualified domain name that your cartridge is a part of (may or may not be equal to |
OPENSHIFT_GEAR_NAME |
OpenShift-assigned name for the gear (may or may not be equal to |
OPENSHIFT_GEAR_UUID |
OpenShift-assigned UUID for the gear |
OPENSHIFT_HOMEDIR |
OpenShift-assigned directory for the gear |
OPENSHIFT_REPO_DIR |
The directory where the developer’s application is "archived" to and will be run from |
OPENSHIFT_SECRET_TOKEN |
A unique 128 character string that is unique to your application that may be used for authentication: joining clusters, initial passwords, etc. This variable may be overridden using |
OPENSHIFT_TMP_DIR |
The directory where your cartridge may store temporary data |
TMPDIR |
Alias for |
TMP |
Alias for |
-
OPENSHIFT_{Cartridge-Short-Name}_DIR
-
OPENSHIFT_{Cartridge-Short-Name}_IDENT
-
OPENSHIFT_PRIMARY_CARTRIDGE_DIR
These are variables provided to you for communicating to the application developer. You may add additional variables for your cartridge’s or the packaged software’s needs. You may provide these files in your cartridge’s env
directory or choose to create them in your setup
and install
scripts.
-
OPENSHIFT_MYSQL_DB_HOST
Backwards compatibility (ERB populate fromOPENSHIFT_MYSQL_DB_IP
) -
OPENSHIFT_MYSQL_DB_IP
-
OPENSHIFT_MYSQL_DB_LOG_DIR
-
OPENSHIFT_MYSQL_DB_PASSWORD
-
OPENSHIFT_MYSQL_DB_PORT
-
OPENSHIFT_MYSQL_DB_SOCKET
-
OPENSHIFT_MYSQL_DB_URL
-
OPENSHIFT_MYSQL_DB_USERNAME
-
OPENSHIFT_PHP_LOG_DIR
-
OPENSHIFT_PHP_DIR
Some variables may be dictated by the software you are packaging:
-
JENKINS_URL
-
JENKINS_USERNAME
-
JENKINS_PASSWORD
Your environment variables should be prefixed with OPENSHIFT_{cartridge short name}_
to prevent overwriting other cartridge variables in the packaged software’s process environment space.
By convention, an environment variable whose value is a directory should have a name that ends in _DIR
and the value should have a trailing slash. The software you are packaging may have environment variable requirements of its own, for example: JENKINS_URL
; these would be added to your env
directory or included in shim code in your bin
scripts.
Cartridge-provided environment variables are not validated by the system. Your cartridge may fail to function if you write invalid data to these files.
You may provide ERB templates in the env
directory (see above for details). ERB templates in the env
directory will be processed before setup
is called.
The PATH
variable is set by OpenShift with the base being /etc/openshift/env/PATH
. If you provide an OPENSHIFT_{Cartridge-Short-Name}_PATH_ELEMENT
, OpenShift will include the value when building the PATH
when your scripts are run or an application developer does an interactive log on.
Cartridges may need to act when another cartridge is added or removed from an application. OpenShift supports a simple publish/subscribe system which allows cartridges to communicate in the context of these events.
The Publishes
and Subscribes
sections of the cartridge manifest.yml
are used to express the event support for a given cartridge.
Publish events are defined via the manifest.yml
for the cartridge, in
the following format:
Publishes:
<event name>:
Type: "<event type>"
...
When a cartridge is added to an application, each entry in the Publishes
section of the manifest is used to construct events dispatched to other cartridges in the application. For each publish entry, OpenShift will attempt to execute a script named hooks/<event name>
:
hooks/<event name> <gear name> <namespace> <gear uuid>
All lines of output (on stdout) produced by the script will be joined by single spaces and used as the input to matching subscriber scripts. All cartridges which declare a subscription whose Type
matches that of the publish event will be notified.
Subscriptions to events published by other carts are defined via the manifest.yml
for the cartridge, in the following format:
Subscribes:
<event name>:
Type: "<event type>"
...
When a cartridge publish event is fired, the subscription entries in the Subscribes
section whose Type
matches that of the publish event will be processed. Subscriptions which have a Type
that starts with ENV:
are processed differently, as described below. For each matching subscription event, OpenShift will attempt to execute a script named hooks/<event name>
:
hooks/<event name> <gear name> <namespace> <gear uuid> <publish output>
The format of the <publish output>
input to the subscription script is defined by the implementation of the publisher script, and so the cartridge subscription script must have an awareness of the output format of the matching publish script.
Subscription types that start with ENV:
have special designation as environment variable subscriptions. For these subscriptions the event hook script hooks/<event name>
is optional. If this script is not present or present but not executable, a specialized built-in event hook is used.
The built-in event hook imports environment variables from any matching Publishes
sections of other cartridges added to the application in question. A typical example where this is useful would be setting up connection credentials in a web cartridge for a database add-on cartridge.
There are two forms of this subscription type: the wildcard type, which is usually what you want to use, and the targeted type.
It’s often useful to pull in environment variables from all add-on cartridges within an application, particularly for web cartridges. For these instances, the ENV:*
subscription type is provided. When a cartridge with this this subscription type is added to an application, all other cartridges in the application are scanned for ENV:
type event publications. These are then processed automatically as detailed above.
The convention for adding the ENV:*
subscription to a cartridge manifest is as follows:
Subscribes:
set-env:
Type: ENV:*
Required: false
In most cases, it is appropriate to use the special wildcard subscription type format described above. For the small remainder of cases, there is the targeted ENV:
subscription form. This allows a cartridge author to control specifically which published environment variable event types a cartridge will use to pull in environment variables.
A targeted ENV:
subscription takes the same format as a normal subscription event, with a particular event type specified as in the following example:
Suppose the fictitious "AwesomeSQL" cartridge publishes environment variables with the following manifest entry:
Publishes:
publish-awesomesql-connection-info:
Type: "ENV:NET_TCP:db:awesomesql"
The corresponding subscription event would be written thus:
Subscribes:
set-awesomesql-connection-info:
Type: "ENV:NET_TCP:db:awesomesql"
Consider a simple example of a PHP cartridge which can react when MySQL is added to an application, so that it can set environment variables on the gear to be able to connect to the newly added MySQL cartridge on a different gear.
This requires a Subscribes
section in the PHP cartridge manifest.yml
:
Subscribes:
set-mysql-connection-info:
Type: "NET_TCP:db:mysql"
And a Publishes
section in the MySQL cartridge manifest.yml
:
Publishes:
publish-mysql-connection-info:
Type: "NET_TCP:db:mysql"
The PHP cartridge implements a script in hooks/set-mysql-connection-info
, and the MySQL cartridge implements a script in hooks/publish-mysql-connection-info
.
These events and scripts are matched on the basis of the string value in Type
("NET_TCP:db:mysql"
).
The publish-mysql-connection-info
script could output the host, port, and password to connect to the MySQL instance, and it will be fed as input to the set-mysql-connection-info
script in the PHP cart when MySQL is added to an application that has PHP installed.
For example, consider the following output from the publish-mysql-connection-info
in the MySQL cartridge:
OPENSHIFT_MYSQL_DB_USERNAME=username; OPENSHIFT_MYSQL_DB_PASSWORD=password; OPENSHIFT_MYSQL_DB_HOST=hostname; OPENSHIFT_MYSQL_DB_PORT=port; OPENSHIFT_MYSQL_DB_URL=url;
This would be fed as input to hooks/set-mysql-connection-info
in the PHP cartridge, as follows:
hooks/set-mysql-connection-info gear_name namespace gear_uuid 'OPENSHIFT_MYSQL_DB_USERNAME=username;OPENSHIFT_MYSQL_DB_PASSWORD=password;OPENSHIFT_MYSQL_DB_HOST=hostname;OPENSHIFT_MYSQL_DB_PORT=port;OPENSHIFT_MYSQL_DB_URL=url;'
The set-mysql-connection-info
is responsible for being capable of parsing the final argument and extracting the values provided.
OpenShift provides a snapshot/restore feature for user applications. This feature is meant to allow OpenShift application developers to:
-
Capture the state ('snapshot') of their application and produce an archive of that state.
-
Use a previously taken snapshot of an application to restore the application to the state in the snapshot.
-
Use a previously taken snapshot of an application to restore a new application to the state in the snapshot. This could be merely renaming an application or copying an application.
OpenShift uses the tar
command when backing up and restoring the gear that contains your cartridge. The file metadata/managed_files.yml
snapshot_exclusions
entry contains an array of patterns of files that will not be backed up or restored. If you exclude files from being backed up and restored you need to ensure those files are not required for your cartridge’s operation.
The file metadata/managed_files.yml
restore_transforms
entry contains scripts that will be used to transform file names during restore.
Both entries are optional and may be omitted. Empty files will be ignored. Patterns are from the OPENSHIFT_HOMEDIR
directory rather than your cartridge’s directory. See the man page for tar
(the --transform
and --exclude-from
options) for more details.
Cartridge developers should preserve the state of the cartridge in all (pre|post)-(restore|snapshot) scripts. Cartridge state should be set back to the original state before this script was invoked.
OpenShift creates an archive during snapshot
as follows:
-
OpenShift stops the application by invoking
gear stop
. -
OpenShift invokes
control pre-snapshot
for each installed cartridge in the gear. Cartridges may control their serialization in the snapshot by implementing this control action in conjunction with exclusions (example: cartridge authors want to snapshot/restore to/from a database dump instead of a database file). -
OpenShift builds a list of exclusions by reading the
snapshot_exclusions
list from themetadata/managed_files.yml
file for each cartridge in the gear. -
OpenShift creates an archive in tar.gz format and writes it to STDOUT for consumption by the client tools. The following exclusions are used in addition to the list created from cartridges:
-
Gear user
.tmp
,.ssh
,.sandbox
-
Application state file (
app-root/runtime/.state
) -
Bash history file (
$OPENSHIFT_DATA_DIR/.bash_history
)
-
-
OpenShift invokes
control post-snapshot
for each installed cartridge in the gear. -
Based on the state of application before snapshot, OpenShift will either stop or start the gear.
OpenShift restores an application from an archive as follows:
-
OpenShift prepares the application for restoration.
-
If the archive contains a git repo, the platform invokes
gear prereceive
. -
Otherwise, the platform invokes
gear stop
. -
OpenShift invokes
control pre-restore
for each installed cartridge in the gear. This allows cartridges that control their snapshotted state to prepare their cartridges for restoration (example: delete old database dump, if present). -
OpenShift builds a list of transforms to apply by reading the
restore_transforms
entries from themetadata/managed_files.yml
file of each cartridge installed in the gear. -
OpenShift extracts the archive into the gear user’s home directory, overwriting existing files, and applying the transformations obtained from cartridges.
-
OpenShift invokes
control post-restore
for each installed cartridge in the gear (example: delete new database dump that the db was restored from). -
OpenShift resumes the application.
-
If the archive contains a git repo, OpenShift invokes
gear postreceive
. -
Based on the state of application before restore, OpenShift will either stop or start the gear.
ServerRoot "<%= ENV['OPENSHIFT_HOMEDIR'] + "/ruby-1.8" %>" DocumentRoot "<%= ENV['OPENSHIFT_REPO_DIR'] + "/public" %>" Listen <%= ENV['OPENSHIFT_RUBY_IP'] + ':' + ENV['OPENSHIFT_RUBY_PORT'] %> User <%= ENV['OPENSHIFT_GEAR_UUID'] %> Group <%= ENV['OPENSHIFT_GEAR_UUID'] %> ErrorLog "|/usr/sbin/rotatelogs <%= ENV['OPENSHIFT_HOMEDIR']%>/ruby-1.8/logs/error_log-%Y%m%d-%H%M%S-%Z 86400" CustomLog "|/usr/sbin/rotatelogs <%= ENV['OPENSHIFT_HOMEDIR']%>/logs/access_log-%Y%m%d-%H%M%S-%Z 86400" combined PassengerUser <%= ENV['OPENSHIFT_GEAR_UUID'] %> PassengerPreStart http://<%= ENV['OPENSHIFT_RUBY_IP'] + ':' + ENV['OPENSHIFT_RUBY_PORT'] %>/ PassengerSpawnIPAddress <%= ENV['OPENSHIFT_RUBY_IP'] %> PassengerUseGlobalQueue off <Directory <%= ENV['OPENSHIFT_REPO_DIR]%>/public> AllowOverride all Options -MultiViews </Directory>
When changes are pushed to an application’s Git repository, OpenShift will build and deploy the application using the updated changes from the repository. The specific build lifecycle which manages the build process changes depending on the presence of a builder cartridge within the application.
When no builder cartridge has been added to the application, changes pushed to the application Git repository result in the execution of the default build lifecycle. The default lifecycle consists of a build
and deploy
phase, each of which aggregates several steps.
In this lifecycle, OpenShift manages the start and stop of the application, as well as moves the newly committed code into $OPENSHIFT_REPO_DIR
. All other specific behaviors are defined by the primary cartridge as well as any user action hooks present.
Note
|
User action hooks are assumed to reside in $OPENSHIFT_REPO_DIR/.openshift/action_hooks .
|
During the build
phase:
-
The application is stopped.
-
The primary cartridge
pre-receive
control action is executed. -
The primary cartridge
pre-repo-archive
control action is executed. -
A new deployment directory
$OPENSHIFT_HOMEDIR/app-deployments/$date_$time
is created with repo and dependencies subdirectories.-
The dependencies directory can be referred to as
$OPENSHIFT_DEPENDENCIES_DIR
in any of the cartridge scripts including setup/install/post_install. Contents placed in this directory are synced to additional gears (both for CI and for scale-up). If your cartridge requires a particular directory structure for dependencies, you should symlink your cartridge directory structure into$OPENSHIFT_DEPENDENCIES_DIR
. -
There is also an
$OPENSHIFT_BUILD_DEPENDENCIES_DIR
which is the appropriate place to put build time only dependencies such as maven artifacts.
-
-
All dependencies from the active deployment (
$OPENSHIFT_HOMEDIR/app-root/runtime/dependencies
) are copied (or moved if$OPENSHIFT_KEEP_DEPLOYMENTS
== 1) to$OPENSHIFT_HOMEDIR/app-deployments/$date_$time/dependencies
-
Starting with the oldest deployment, previous deployments are removed until the number of deployments in app-deployments ⇐ the value of
$OPENSHIFT_KEEP_DEPLOYMENTS
(if necessary) -
The contents of the git repo for the current deployment branch are unpacked into
$OPENSHIFT_HOMEDIR/app-deployments/$date_$time/repo
. This step is the only time the application source code is copied by OpenShift during this lifecycle. -
The primary cartridge
pre-build
control action is executed. -
The
pre_build
user action hook is executed, if present. -
The primary cartridge
build
control action is executed. -
The
build
user action hook is executed.
Next, during the prepare
phase:
-
The
prepare
user action hook is executed, if present. -
The deployment id and checksum of deployment contents are calculated
-
$OPENSHIFT_HOMEDIR/app-deployments/by-id/$deployment_id
is created and points to../app-deployments/$date_time
Next, during the distribute
phase:
-
If the app is scalable, the new deployment will be synced to all child gears
Next, during the activate
phase:
-
$OPENSHIFT_HOMEDIR/app-root/runtime/repo
is updated to point at../../app-deployments/$date_$time/repo
-
$OPENSHIFT_HOMEDIR/app-root/runtime/dependencies
is updated to point at../../app-deployments/$date_$time/dependencies
-
The primary cartridge
update-configuration
control action is executed. -
All secondary cartridges in the application are started.
-
The primary cartridge
deploy
control action is executed. -
The
deploy
user action hook is executed, if present. -
The primary cartridge is started or restarted depending on the current status of the cartridge (the application is now fully started).
-
The primary cartridge
post-deploy
control action is executed. -
The
post_deploy
user action hook is executed, if present. -
If the app is scalable, SSH to each child gear and execute
gear activate $deployment_id
which performs all the activation steps (except this one) -
Write activation time to
$OPENSHIFT_HOMEDIR/app-deployments/$date_$time/metadata.json
At this point, the application has been fully built and restarted.
The current deployment can be archived, creating an artifact which can be re-deployed later with rhc archive-deployment
.
From a cartridge perspective, binary deploy is very similar to build and deploy without the build. Instead the built artifacts and dependencies are provided and the deploy steps start at prepare
. Binary deployment must be enabled with rhc env-set OPENSHIFT_DEPLOYMENT_TYPE=binary
.
If a builder cartridge is present in the application, changes pushed to the application Git repository will execute using an alternate build lifecycle which hands over operations to the builder cartridge. In this lifecycle, OpenShift provides no specific behavior for the build beyond giving the builder cartridge the opportunity to perform work. The sequence of events follows:
During the Git pre-receive
hook:
-
The builder cartridge
pre-receive
control action is executed.
During the Git post-receive
hook:
-
The builder cartridge
post-receive
control action is executed.
Any build implementation should take care to avoid duplicating source or copying artifacts any more than necessary. The space a cartridge’s build implementation consumes during the build cycle is the application developer’s, and so cartridge authors should take care to be as conservative as possible.
[cart_locking]: #cartridge-locking [snapshot]: #backing-up-and-restoring-your-cartridge [erb_processing]: #erb-processing [erb]: http://ruby-doc.org/stdlib-1.9.3/libdoc/erb/rdoc/ERB.html [locking_ruby]: http://www.ruby-doc.org/docs/ProgrammingRuby/html/taint.html).
The OpenShift runtime contains an upgrade system used to upgrade the cartridges in a gear to the latest available version and to apply gear-scoped changes which are orthogonal to cartridges to a gear. The oo-admin-upgrade
command provides the CLI for the upgrade system and can be used to upgrade all gears in an OpenShift environment, all gears on a node, or a single gear. This command queries the openshift broker to determine the locations of the indicated gears to migrate and makes mcollective calls to trigger the upgrade for a gear.
During upgrades, OpenShift follows the following high-level process to upgrade a gear:
-
Load the gear upgrade extension, if configured.
-
Inspect the gear state.
-
Run the gear extension’s pre-upgrade method, if it exists.
-
Compute the upgrade itinerary for the gear.
-
If the itinerary contains an incompatible upgrade, stop the gear.
-
Upgrade the cartridges in the gear according to the itinerary.
-
Run the gear extension’s post-upgrade method, if it exists.
-
If the itinerary contains an incompatible upgrade, restart and validate the gear.
-
Clean up after the upgrade by deleting pre-upgrade state and upgrade metadata.
The upgrade process must be re-entrant; if it fails or times out, a subsequent upgrade operation must pick up where the last one left off without losing any data about which operations must be performed to fully upgrade a gear. The upgrade itinerary stores information about which cartridges in a gear must be upgraded and which type of upgrade to perform.
There are two types of cartridge upgrade process: compatible and incompatible. Whether an upgrade from version X to version Y is compatible is driven by the presence of version X in version Y’s Compatible-Versions
manifest element. Though compatible and incompatible upgrades differ in various ways, the chief difference is that when an incompatible upgrade is to be applied to any cartridge in a gear, that gear is stopped before the cartridge upgrades are performed and restarted after all cartridges have been upgraded.
The upgrade itinerary is computed as follows for each cartridge in a gear:
-
Read in the current IDENT of the cartridge.
-
Select the name and software version of the cartridge from the cartridge repository; this will yield the manifest for the latest version of the cartridge. If the manifest does not exist in the cartridge repository or does not include the software version, skip the cartridge.
-
If the latest manifest is for the same cartridge version as that currently installed in the gear, skip the cartridge unless the
ignore_cartridge_version
parameter is set. If theignore_cartridge_version
parameter is set, record an incompatible upgrade for the cartridge in the itinerary. (TODO: case where manifest declares itself as compatible version). -
If the latest manifest includes the current cartridge version in the
Compatible-Versions
element, record a compatible upgrade for the cartridge in the itinerary. Otherwise, record an incompatible upgrade for the cartridge in the itinerary.
The compatible upgrade process for a cartridge is as follows:
-
The new version of the cartridge is overlaid in the gear.
-
The files declared in the
Processed-Templates
section of the cartridge’smanaged-files.yml
are removed. -
The cartridge directory is unlocked.
-
The cartridge directory is secured.
-
If the cartridge provides an
upgrade
script, that script is executed. -
The cartridge directory is locked.
The incompatible upgrade process for a cartridge is as follows:
-
The cartridge is stopped.
-
The files and directories declared in the
setup_rewritten
section of the cartridge’smanaged_files.yml
are removed. -
The new version of the cartridge is overlaid in the gear.
-
The cartridge directory is unlocked.
-
The cartridge directory is secured.
-
If the cartridge provides an
upgrade
script, that script is executed. -
If the cartridge provides a
setup
script, that script is executed. -
The erb templates for the cartridge are processed.
-
The cartridge directory is locked.
-
New endpoints for the cartridge are created.
-
The frontend is connected.
-
The cartridge is started.
A cartridge may provide an upgrade
script in the bin
directory which will be executed during the upgrade process. The purpose of this script is to allow for arbitrary actions to occur during the upgrade process which are not accounted for by the compatible or incompatible processes. If the upgrade
script is provided, it will be passed the following arguments:
-
The software version of the cartridge.
-
The current cartridge version.
-
The cartridge version being upgraded to.
A non-zero exit code from this script will result in the upgrade operation failing until the exit code is corrected.