A Rest API service and notification service for SITA AMS
Report Bug
Request Feature
Table of Contents
SITA AMS has a set of APIs that is quite comprehensive, however:
- They can be difficult to use
- If used without discretion, they can impact system performance.
- The data is provided in a format not easily used with modern frameworks
- They have limited capability to refine the search for particular data
- Response time of the API can be affected by other operations taking place on the AMS Server
- All users receive the same data from the API, regardless of any sensitivities
- The granularity of notifaction messages is very coarse
This project addreses these issues by introducing a Restful API Server to service user requests.
The service loads and caches flights from AMS and then continually listens for update notification from AMS to maintain the cache. Periodically, the service "advances" the window operating times of flights in the cache by requesting data from AMS. At the same time the service prunes old flights from the cache by removing flights that have fallen out of the window of configured flight operating times
The service exposes an API to retrieve flights and to retrieve the allocation of resources out of the cache without needing to go to AMS. Users can provide identity information in their API request to recieve a customised set of data or if no identity is provided, then they will receive a default set of publicly available data
The service also provides Push notification of changes and regular scheduled updates to subscribers via a WebHooks mechanism or via a RabbitMQ Exchange
- Isolate AMS from each individual API call
- Return results in less than 1 second
- Cater for multiple airports or instance of AMS using a single instance of the API
- Discriminate users accessing the API and provide only the data they are entitled to see
- Provide enough richness in the API to cover a variety of operational Use Cases
- Minimise memory usage and growth of heap space
- Do not introduce any new infrastructure components not already present in a typical AMS setup
- Limit administration tasks to configuration only.
- Include the tools to test performance and demonstrate capability
- Provide a change notification service where users can define the types of changes they are interested in
- Provide a no configuration change notification service for annonymous users
In addition to the main service (opapi.exe) project includes four utility programs:
- opapiseeder.exe This utility is used to seed the serive with demonstration flights and allocation when the servoce is run in Demonstration or Performance Test Mode
- webhookclient.exe The service has the ability to send change notifications and status updates via a WebHooks implementation. This program allows you to run a demonstration webhook client to deomonstate this capability
- rabbitclient.exe Same functionality as the webhookclient except for RabbitMQ clients
- perftestclient.exe This utility allows the response time performance of the API to be tested over a period of time by making repeated call to the API and recording response times
The service is built using the Go ( version 1.20 ) programming language. No other runtime software components are require other than the service itself
This is not official software from SITA. It was built as a learning exercise to learn the Go programming language, using a real world problem that I am familiar with.
No support or warranty should be inferred. There is no gaurantee for fitness of purpose
No endorsement of this software be SITA should be inferred
The information on using the SITA AMS API was obtained from publicly available information
To run the service, either download the latest release, or clone this repository and build it yourself in and IDE that supports Go 1.20
The API service can be installed to run as a windows service or from the Windows command line prompt
The service does not require any additional software componets. The service self hosts itself according the the configuration in service.json file
- To install and start as a Windows Service. Must be logged on with Administrator privelege
C:\ProgramFiles\opapi\opapi.exe install C:\ProgramFiles\opapi\opapi.exe start
- To stop the windows service and uninstall. Must be logged on with Administrator privelege
C:\ProgramFiles\opapi\opapi.exe stop C:\ProgramFiles\opapi\opapi.exe uninstall
- To run from command line as any user
C:\ProgramFiles\opapi\opapi.exe run
Responses to the Rest API request, change notifications and subscription notifications are provided in JSON format. API requests will include meta data in the message to describe the response. Samples of the messages can be found at the links below
- Get Flights Response Sample
- Flight Create Notification Sample
- Flight Create Notification Sample
- Flight Deleted Notification Sample
- Get Allocations Sample
- Get Configured Resources Sample
This service exposes three API endpoints to retreive data on flights, resource allocations and configured resources:
- /getFlights
- /getAllocations
- /getConfiguredResources
The APIs are accessed via HTTP GET Requests and return data in JSON format
The HTTP Get request header should include a parameter called "Token".
The value of "Token" is assigned by the system administrator to identify your user profile which defines your rights and capabilities to acces the APIs
If the token header is not present, you will be assigned the rights of the "default user", if one is configured by the administrator
Retreive flight details
Parameter | Description | Example |
---|---|---|
Airport | Three letter IATA airport code to the desired airport | /getFlights/APT |
al or airline | Two letter IATA code for the airline, eg. BA, DL, LH, MH (default: all airlines) | /getFlights/APT?al=QF |
flt or flight | Flight Number, eg. QF001, EK23, BA007 (default: all flights | /getFlights/APT?flt=QF001 |
d or direction | The direction of flight relative to the home airport. either 'Arr' or 'Dep' | /getFlights/APT?d=Arr |
r or route | The route of the flight | /getFlights/APT?r=MEL |
from | Number of hours relative to 'now' for the earliest scheduled time of operation for the flight, eg. -3 (default: -12 | /getFlights/APT?from=-12 |
to | Number of hours relative to 'now' for the latest scheduled time of operation for the flight, eg. 12 (default: 24) | /getFlights/APT?to=48 |
updatedSince | Return records that have been updated from the date, e.g. 2023-07-16T13:00:00 | /getFlights/APT?updatedSince=2023-07-16T13:00:0 |
{custom field name} | Return records have the specified custom field name equal to the specified value. Users will only be able to search on the custom fields they have been granted access to. (see below) | /getFlights/APT?Sh--_GroundHandler=EAS |
max | Limit the total number of flights returned to the number specified | /getFlights/APT?max=5 |
Find the flights from now until 12 hours from now
/getFlights/APT?from=0&to=12
Find the Qantas flights from now until 12 hours from now
/getFlights/APT?al=QF&from=0&to=12
Find the flights arriving from Melbourne
/getFlights/APT?route=MEL&d=Arr
Find all the flight where the custom field name Sh--_GroundHandler of the assigned flight is EAS
/getFlights/APT?Sh--_GroundHandler=EAS
Retreive flights allocated to resources
Parameter | Description | Example |
---|---|---|
Airport | Three letter IATA airport code to the desired airport | /getAllocations/APT |
flt or flight | Flight Number, eg. QF001, EK23, BA007 (default: all flights) | /getAllocations/APT?flt=QF001 |
al or airline | Two letter IATA code for the airline, eg. BA, DL, LH, MH (default: all airlines | /getAllocations/APT?flt=QF |
rt or resourceType | One of CheckIn, Gate, Stand, Carousel, Chute. (default: all types are returned) | getAllocations/APT?rt=Gate |
id or resource | The name of the individual reource to query. Query must include the resourceType parameter (default: all resources) | /getAllocations/APT?rt=Gate&id=100 |
from | Number of hours relative to 'now' to start looking for allocations, eg. -3 (default:-12) | getAllocations/APT?from=-12 |
to | Number of hours relative to 'now' to stop looking for allocations, eg. 12 (default: 24) | getResources/APT?to=7 |
sort | Either "resource" or "time" to specify the sort order of the allocations returned (default: resource) | /getAllocations/APT?sort=time |
updatedSince | Return records that have been updated from the date, e.g. 2023-07-16T13:00:00 | /getAllocations/APT?upatedSince=2023-07-16T13:00:00 |
Find the flights allocated to checkin desk 100 from now until 12 hours from now
/getResources/APT?from=0&to=12&rt=CheckIn&id=100
Find all the resources allocated to flight QF100
/getResources/APT?flt=QF100
Find all the resources allocated to Emirates (EK)
/getResources/APT?al=EK
Find all the resources allocated to British Airways (BA) for the next 3 days
/getResources/APT?al=BA&from=0&to=72
Find all the resources where the custom field name Sh--_GroundHandler of the assigned flight is
EAS
/getResources/APT?Sh--_GroundHandler=EAS
Retreive the configured resources for the airport
Parameter | Description | Example |
---|---|---|
Airport | Three letter IATA airport code to the desired airport | /getConfiguredResources/APT |
{Resource Type} | One of CheckIn, Gate, Stand, Carousel, Chute. (default: all types are returned) | /getConfiguredResources/APT/Gate |
The execution of the service is controlled by the configuration in the file service.json in the directory the application is installed in. An example of the contents of the service.json file is shown below
{
"ServiceName": "GetFlightAndResourceService",
"ServiceDisplayName": "GetFlight and Resource Rest API",
"ServiceDescription": "A HTTP/JSON Rest Service for retrieving flights and resource allocations from AMS",
"ServiceIPport": "127.0.0.1:8081",
"ScheduleUpdateJob": "02:00:00",
"ScheduleUpdateJobIntervalInHours": 1,
"ScheduleUpdateJobIntervalInMinutes": -1,
"DebugService": true,
"TraceService": false,
"UseHTTPS": false,
"UseHTTPSUntrusted": false,
"KeyFile": "keyFile",
"CertFile": "certFile",
"TestHTTPServer": false,
"LogFile": "c:/Users/dave_/Desktop/Logs/process.log",
"RequestLogFile": "c:/Users/dave_/Desktop/Logs/request.log",
"MaxLogFileSizeInMB": 50,
"MaxNumberLogFiles": 3,
"EnableMetrics": true,
"MetricsLogFile": "c:/Users/dave_/Desktop/Logs/performance.log",
"AdminToken": "davewashere",
"NumberOfChangePushWorkers":7,
"NumberOfSchedulePushWorkers":5,
"UseGob":true
}
Parameter | Description | Notes |
---|---|---|
ServiceName | GetFlightAndResourceService | |
ServiceDisplayName | The service display name e.g."GetFlight and Resource Rest API" | |
ServiceDescription | The service description e.g. "A HTTP/JSON Rest Service for retrieving flights and resource allocations from AMS" | |
ServiceIPport | The IP address and port number for the service to bind to, e.g. 127.0.0.1:8081 | |
ScheduleUpdateJob | 02:00:00 | |
ScheduleUpdateJobIntervalInHours | The interval between running update jobs to update the repository from AMS in hours | |
ScheduleUpdateJobIntervalInMinutes | The interval between running update jobs to update the repository from AMS in minutes | This is a seperate schedule to the one specified by the "hours" schedule |
DebugService | ||
TraceService | ||
UseHTTPS | Set to "true" to run the service using HTTPS. If true, then the KeyFile and CertFile paramters must be set | "false" by default |
UseHTTPSUntrusted | Set to true to run the service using HTTPS with a locally generated certificate | |
KeyFile | keyFile | |
CertFile | certFile | |
TestHTTPServer | ||
LogFile | The log file name to log serive debug and error messages e.g. c:/Users/dave_/Desktop/Logs/process.log | |
RequestLogFile | The log file name to log API requests e.g. c:/Users/dave_/Desktop/Logs/request.log | |
MaxLogFileSizeInMB | The maximum size of the application log file | |
MaxNumberLogFiles | When the log file have reached their maximum size they will be archived. This parameter specifies how many archive logs to keep | |
EnableMetrics | true | |
MetricsLogFile | c:/Users/dave_/Desktop/Logs/performance.log | |
AdminToken | The header token to identify the user with administrator capability | |
NumberOfChangePushWorkers | The number of worker Go processes for managing change notifications | |
NumberOfSchedulePushWorkers | The number of worker Go processes for managing distribution of subscription updates | Maximum value should not exceed the total number of subscriptions |
UseGob | Under normal operation, the service will cache information in memory. This can result in significant memory usage if there is a large number of flights or allocation. If UseGob is set to "true", the service will use a file based caching mechanism which means the service memory usage will not vary according to the number of flights. API response times may be impacted and the return time may be in the hundreds of milliseconds rather than the tens of milliseconds for memory based caching |
The memory used by the service is variable. The primary factors in memory usage is the number of flights held in the service's cache and the number of custom fields defined for flights withing AMS.
Memory usage can be reduced by setting the environment variable GOMEMLIMIT to the target memory usage limit.
e.g. GOMEMLIMIT=120MiB
This acts as a target for the services garbage collection system to aim for when freeing up memory
Each airport to be serviced by the API service needs to be configured in the file airports.json in the directory the application is installed in. More than one airport can be configured.
An example of the contents of the service.json file is shown below
{
"Repositories": [
{
"AMSAirport": "ABC",
"AMSToken": "0ab7d73d-e93a-480b-ba8c-a35943161cb0",
"AMSSOAPServiceURL": "http://localhost/SITAAMSIntegrationService/v2/SITAAMSIntegrationService",
"AMSRestServiceURL": "http://localhost/api/v1/",
"FlightSDOWindowMinimumInDaysFromNow": -3,
"FlightSDOWindowMaximumInDaysFromNow": 20,
"ListenerType":"MSMQ",
"NotificationListenerQueue": ".\\private$\\tow_tracker",
"LoadFlightChunkSizeInDays": 4,
"RabbitMQConnectionString": "amqp://amsauh:amsauh@localhost:5672/amsauh",
"RabbitMQExchange": "Test",
"RabbitMQTopic": "AMSX.Notify",
"PublishChangesRabbitMQConnectionString": "amqp://amsauh:amsauh@localhost:5672/amsauh",
"PublishChangesRabbitMQExchange": "Test",
"PublishChangesRabbitMQTopic": "AMSJSON.Notify"
},
{
"AMSAirport": "DEF",
"AMSToken": "0ab7d73d-e93a-480b-ba8c-a35943161cb0",
"AMSSOAPServiceURL": "http://localhost/SITAAMSIntegrationService/v2/SITAAMSIntegrationService",
"AMSRestServiceURL": "http://localhost/api/v1/",
"FlightSDOWindowMinimumInDaysFromNow": -3,
"FlightSDOWindowMaximumInDaysFromNow": 20,
"ListenerType":"MSMQ",
"NotificationListenerQueue": ".\\private$\\tow_tracker",
"LoadFlightChunkSizeInDays": 4,
"RabbitMQConnectionString": "amqp://amsauh:amsauh@localhost:5672/amsauh",
"RabbitMQExchange": "Test",
"RabbitMQTopic": "AMSX.Notify",
"PublishChangesRabbitMQConnectionString": "amqp://amsauh:amsauh@localhost:5672/amsauh",
"PublishChangesRabbitMQExchange": "Test",
"PublishChangesRabbitMQTopic": "AMSJSON.Notify"
}
]
}
Parameter | Description | Notes |
---|---|---|
AMSAirport | "DEF" | |
AMSToken | "0ab7d73d-e93a-480b-ba8c-a35943161cb0" | |
AMSSOAPServiceURL | "http://localhost/SITAAMSIntegrationService/v2/SITAAMSIntegrationService" | |
AMSRestServiceURL | "http://localhost/api/v1/" | |
FlightSDOWindowMinimumInDaysFromNow | -3 | |
FlightSDOWindowMaximumInDaysFromNow | 20 | |
ListenerType | "MSMQ" | |
NotificationListenerQueue | ".\private$\tow_tracker" | |
LoadFlightChunkSizeInDays | 4 | |
RabbitMQConnectionString | "amqp://amsauh:amsauh@localhost:5672/amsauh" | |
RabbitMQExchange | "Test" | |
RabbitMQTopic | "AMSX.Notify" | |
PublishChangesRabbitMQConnectionString | "amqp://amsauh:amsauh@localhost:5672/amsauh" | |
PublishChangesRabbitMQExchange | "Test" | |
PublishChangesRabbitMQTopic | "AMSJSON.Notify" |
Access to the service can be controlled by tokens that are passed in the header of the request. The configuration of the user controls the airports, airline and custom fields that the user has access to. The user configuration can also include subscription to update notification and change notifications. COnfiguration of users is in the users.json file
If the user does not provide a token for a valid configured user, then they are granted the access rights of the "default" user if configured.
Below is an example of the users.json file with two users configured.
- The "Default User" has restricted access just the ABC and APT airports. They are also restricted to flight information on WY and QF flights. The AllowedCustomFields array defines the custom field data that will be returned to them if available; not other custom fields will be returned to the user.
- The second defined user, "Super User" has access to all airports, airlines and custome fields. The "*" in the configuration gives access to ALL.
- The Key parameter is the value of the Token header attribute that the users supplies to be identified with this user
Between these extremes, other users can be configured with appropriate access rights configured for each user
{
"Users": [
{
"Enabled": true,
"UserName": "Default User",
"Key": "default",
"AllowedAirports": [
"ABC", "APT"
],
"AllowedAirlines": [
"WY",
"QF",
],
"AllowedCustomFields": [
"FlightUniqueID",
"SYS_ETA",
"FlightUniqueID",
"Il--_DisembarkingFirstPad",
"Sh--_GroundHandler",
"Il--_TotalMalePax",
"S---_Terminal",
],
"UserChangeSubscriptions": [],
"UserPushSubscriptions": []
},
{
"Enabled": true,
"UserName": "Super User",
"Key": "reallyhardtoguessstring!@#*&^",
"AllowedAirports": [
"*"
],
"AllowedAirlines": [
"*"
],
"AllowedCustomFields": [
"*",
],
"UserChangeSubscriptions": [],
"UserPushSubscriptions": []
},
]
}
A user can have zero, one or more change notification subscriptions confiured. The change subscription defines the types of changes that the user in iterested in, e.g an aircraft type change, a flight delete, etc. When one of the interested changes occurs, the service will push the notification to the defined end point for the user. The defined end point can be a WebHooks client or a RabbitMQ Exchange
{
"Users": [
{
"Enabled": true,
"UserName": "Airport Stakeholder",
"Key": "!@#$rtyuoiad6$$%",
"AllowedAirports": [
"ABC"
],
"AllowedAirlines": [
"*"
],
"AllowedCustomFields": [
"*",
],
"UserChangeSubscriptions": [
{
"Enabled": true,
"EnableInDemoMode":false,
"Airport": "APT",
"CreateFlight": true,
"DeleteFlight": true,
"UpdateFlight": true,
"CheckInChange": true,
"GateChange": true,
"StandChange": true,
"CarouselChange": true,
"ChuteChange": true,
"AircraftTypeOrRegoChange": true,
"RouteChange": true,
"LinkedFlightChange":true,
"EventChange": true,
"CustomFieldChange": [
"SYS_ETA"
],
"All":true,
"DestinationURL": "http://localhost:8082/changeEndpoint",
"TrustBadCertificates":true,
"HeaderParameters": [
{"Parameter":"UserDefinedKey_1", "Value":"Secret Provided By Receiving System"},
{"Parameter":"UserDefinedKey_2", "Value":"Some Other Secret Provided By Receiving System"}
],
"PublishChangesRabbitMQConnectionString": "amqp://amsauh:amsauh@localhost:5672/amsauh",
"PublishChangesRabbitMQExchange": "Test",
"PublishChangesRabbitMQTopic": "AMSJSON.Notify",
"RMQEnabled":true,
"HTTPEnabled":true
}
],
"UserPushSubscriptions": []
},
]
}
The subscription can spefify the types of changes the user is interested in receiving. If the flight is changed, but does not contain a change type that hsa been enabled, the the update message will not be sent.
"CreateFlight": true,
"DeleteFlight": true,
"UpdateFlight": true,
"CheckInChange": true,
"GateChange": true,
"StandChange": true,
"CarouselChange": true,
"ChuteChange": true,
"AircraftTypeOrRegoChange": true,
"RouteChange": true,
"LinkedFlightChange":true,
"EventChange": true,
"CustomFieldChange": [
"SYS_ETA"
],
"All":true,
DestinationURL is the endpoint to send the HTTP webhook request to on the client system. The call can be either HTTP or HTTPS. If using HTTPS TrustaAdCertificates can be set to send the request, even if the host certificate is incorrect
"DestinationURL": "http://localhost:8082/changeEndpoint",
"TrustBadCertificates":true,
The HeaderParameters array define the Attribute/Value the will be placed in the header of the HTTP webhook call to the client. These can be used so that the client can validate that the request has come from a known source.
"HeaderParameters": [
{"Parameter":"UserDefinedKey_1", "Value":"Secret Provided By Receiving System"},
{"Parameter":"UserDefinedKey_2", "Value":"Some Other Secret Provided By Receiving System"}
],
The following parameters set the values for a RabbitMQ connection to send the data to. Data is sent to a Rabbit MQ Exchange. This allows maximum flexibility. Clients wanting to receive the data would create a dynamic queue on the RabbitMQ server and bind the queue to the Exchange
"PublishChangesRabbitMQConnectionString": "amqp://amsauh:amsauh@localhost:5672/amsauh",
"PublishChangesRabbitMQExchange": "ClientDistribution",
"PublishChangesRabbitMQTopic": "AMSJSON.Notify",
None, one or both the endpoint types can be set active by setting the parameters below
"RMQEnabled":true,
"HTTPEnabled":true
A user can have zero, one or more push subscriptions configured. A push subscription will send the current state for a set of flights or resources configured in the subscription.
The push will occur at regular intervals as defined in the subscription. The data is sent to a WebHook endpoint and/or published to a RabbitMQ exchange as configured in the subscription.
{
"Users": [
{
"Enabled": true,
"UserName": "Default User",
"Key": "default",
"AllowedAirports": [
"APT"
],
"AllowedAirlines": [
"*"
],
"AllowedCustomFields": [
"FlightUniqueID",
"SYS_ETA"
],
"UserChangeSubscriptions": [],
"UserPushSubscriptions": [
{
"Enabled": true,
"EnableInDemoMode":true,
"PushOnStartUp": true,
"Airport": "AUH",
"SubscriptionType": "Flight",
"Time": "14:00:00",
"ReptitionHours": 1,
"ReptitionMinutes": 1,
"From": -24,
"To": 24,
"Airline": "",
"QueryableCustomFields": [],
"Route": "",
"Direction": "",
"ResourceType": "",
"ResourceID": "",
"DestinationURL": "http://localhost:8082/subscriptionEndPoint",
"HeaderParameters": [
{"Parameter":"UserDefinedKey_1", "Value":"Secret Provided By Receiving System"},
{"Parameter":"UserDefinedKey_2", "Value":"Some Other Secret Provided By Receiving System"}
],
"TrustBadCertificates":true,
"PublishStatusRabbitMQConnectionString": "amqp://amsauh:amsauh@localhost:5672/amsauh",
"PublishStatusRabbitMQExchange": "Test",
"PublishStatusRabbitMQTopic": "AMSJSON.Status",
"RMQEnabled":true,
"HTTPEnabled":true
}
]
},
The service can be run in Demonstration Mode to allow usage and demonstration of the API capability without a connection to AMS. When run in demonstration mode, the service uses the configuration in the file testfiles\test.json to define the airport and the resources available at the airport. Flights and Allocation can be loaded into the system using the opapiseeder.exe program (see below)
C:\ProgramFiles\opapi\opapi.exe demo
When the service is running in Demonstration Mode, it can be seeded with flight and resource allocation data by using the opapiseeder.exe program. The program must be run on the same server as the main opapi service. An example is shown below
C:\ProgramFiles\opapi\opapiseeder.exe demo 5000 500 true
In this example, the service is seeded with 5000 flights, with each flight having 500 custom field entries. The final "true" parameter indicates that the seeder should continue to run an produce random updates every 20 seconds. Setting this final parameter to "false" prevents these random updates.
opapiseeder.exe uses the configuration file testfiles\test.json to hold the configured resources and connection details for connecting to the main opapi service
Performance Test Mode is very similar to Demonstration Mode, the exception being is that the flights are loaded and updated by the opapiseeder.exe program via a RabbitMQ interface, rather than a direct interface in Demonstration Mode. This allows closer approximation to a real life implementation than Demonstration Mode
C:\ProgramFiles\opapi\opapi.exe perfTest
C:\ProgramFiles\opapi\opapiseeder.exe perfTest 5000 500 true
The example WebHooks client program can act help demonstrate the function of the service by acting as a demonstration client. The client will receive Webhook updates from the service and log data on the received content of the message
- To log all received messages to files.
C:\ProgramFiles\opapi\webhookclient.exe localhost:8082 log
- To print out the first 500 characters of the message on the console
C:\ProgramFiles\opapi\webhookclient.exe localhost:8082 debug
- To print out the entire contents of the message on the console
C:\ProgramFiles\opapi\webhookclient.exe localhost:8082 trace
The example Rabbit MQ client program can act help demonstrate the function of the service by acting as a demonstration client. The client will receive Webhook updates from the service and log data on the received content of the message
The parameters are: {RMQ Connection String} {RMQ Exchange} {RMQ Subscription Topic} {RMQ Change Topic} {Log Mode}
- To log all received messages to files.
C:\ProgramFiles\opapi\rabbitclient.exe amqp://rabbituser:rabbitpass@localhost:5672/rabbitvirtualhost Test AMSJSON.Status AMSJSON.Notify Log
- To print out the first 500 characters of the message on the console
C:\ProgramFiles\opapi\rabbitclient.exe amqp://rabbituser:rabbitpass@localhost:5672/rabbitvirtualhost Test AMSJSON.Status AMSJSON.Notify Debug
- To print out the entire contents of the message on the console
C:\ProgramFiles\opapi\rabbitclient.exe amqp://rabbituser:rabbitpass@localhost:5672/rabbitvirtualhost Test AMSJSON.Status AMSJSON.Notify Trace
- Add Changelog
- Add UI to manage configuration
- Add a realtime management and monitoring user interface
- Verify compatibility with UTF-16
- Add change notifications for resource allocation changes
See the open issues for a full list of proposed features (and known issues).
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
) - Commit your Changes (
git commit -m 'Add some AmazingFeature'
) - Push to the Branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
Distributed under the MIT License. See LICENSE.txt
for more information.
Dave Burton: daveontour57@gmail.com
Project Link: https://github.com/daveontour/opapi