Documentation
¶
Overview ¶
package ims provides basic support for Incident Management System (IMS) integration, such as ServiceDesk Plus, ServiceNow, etc.
Index ¶
- Constants
- Variables
- func Connect(imsCf *config.Config, imsType string) iter.Seq[*rest.Client]
- func CorrelationID(data string) string
- func NewClient(clientConfig *ClientConfig) *rest.Client
- func ProcessActionGroup(cf *config.Config, ag ActionGroup, incident Values) bool
- func RegisterEndpoint(method, path string, handler http.HandlerFunc)
- func WriteJSONResponse(w http.ResponseWriter, r *http.Request, status int) error
- type ActionGroup
- type ClientConfig
- type ContextKey
- type Endpoint
- type LogTransport
- type Response
- type Results
- type SnowResult
- type SnowResultsResponse
- type Transformation
- type Values
Constants ¶
const ( PROFILE = "__itrs_profile" INCIDENT_UPDATE_ONLY = "__incident_update_only" INCIDENT_CORRELATION = "__incident_correlation" )
const ( // ServiceNow fields SNOW_CMDB_CI_FIELD = "cmdb_ci" SNOW_CORRELATION_FIELD = "correlation_id" SNOW_SYS_ID_FIELD = "sys_id" SNOW_USER_NAME_FIELD = "user_name" // ServiceNow tables SNOW_SYS_USER_TABLE_DEFAULT = "sys_user" SNOW_INCIDENT_TABLE_DEFAULT = "incident" SNOW_CMDB_TABLE_DEFAULT = "cmdb_ci" // internal fields SNOW_CORRELATION = "__snow_correlation" SNOW_CMDB_CI_DEFAULT = "__snow_cmdb_ci_default" SNOW_CMDB_SEARCH = "__snow_cmdb_search" SNOW_CMDB_TABLE = "__snow_cmdb_table" SNOW_INCIDENT_TABLE = "__snow_table" )
Variables ¶
var Endpoints = []Endpoint{}
Functions ¶
func Connect ¶
Connect returns a sequence of *ClientConfig for each URL in the configuration. The caller can attempt to connect to each configured URL in turn until a successful connection is made.
The order of the URLs is not guaranteed, so the caller should not rely on the order of the URLs in the configuration. The caller should also be prepared to handle connection failures, as some of the URLs may be unreachable or misconfigured.
The configuration keys suported are:
- `url`: a list of URLs to connect to, e.g. `["https://ims1.example.com/api", "https://ims2.example.com/api"]`. The IMS type (e.g. `snow`) will be appended, as required by `ims-gateway`, to the URL when creating the client, so the actual URLs used will be `https://ims1.example.com/api/snow` and `https://ims2.example.com/api/snow`.
- `authentication.token`: the token to use for authentication, e.g. `abc123`
- `timeout`: the timeout for the connection, e.g. `10s`
- `tls.skip-verify`: whether to skip TLS verification, e.g. `true`
- `tls.chain`: a PEM encoded certificate chain to use for TLS verification, e.g. `-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----`
- `trace`: whether to enable HTTP request/response tracing, e.g. `true`
func CorrelationID ¶
CorrelationID generates a correlation ID for the given data. The algorithm used, SHA1, does not have to be cryptographically secure, but should produce a reasonably unique ID for the given data. The same data should produce the same correlation ID, and different data should produce different correlation IDs with a very high probability. The correlation ID is returned as a hexadecimal string.
func NewClient ¶
func NewClient(clientConfig *ClientConfig) *rest.Client
NewClient creates a new rest.Client for the given URL and configuration. The client is NOT cached as each execution is a single request to the first remote proxy that responds, however the underlying http.Client is cached and shared across all rest.Client instances created by this function, so TLS configuration is shared across all clients created by this function. The caller should ensure that the TLS configuration is compatible with all URLs that may be used.
func ProcessActionGroup ¶
func ProcessActionGroup(cf *config.Config, ag ActionGroup, incident Values) bool
ProcessActionGroup evaluates the config structure and if the caller should stop processing (break) then returns `true`. The evaluation is in the following order:
- `if`: one or more strings that are evaluated and the results parsed as a Go boolean (using strconv.ParseBool). As soon as any `if` returns a false value, evaluation stops and the function returns false
- `set`: an object that sets the fields, unordered, to the value passed through expansion with config.ExpandString
- `unset`: unset the list of field names
- `subgroup`: evaluate a sub-group, terminating evaluation if the group includes `break` (after evaluating any `if` actions as true)
- `break`: break returns true to the caller, allow them to stop processing early. This is used to stop evaluation in a parent
- `exit`: stops further processing and exits the program immediately with an exit code given. This is used to stop processing in a parent when the child group has done everything needed and no further processing is required.
func RegisterEndpoint ¶
func RegisterEndpoint(method, path string, handler http.HandlerFunc)
RegisterEndpoint registers an API endpoint for the IMS integration, including the HTTP method, path, and handler function. The path should be relative to the application base path and can include path parameters (e.g. "/create/{id}").
func WriteJSONResponse ¶
WriteJSONResponse writes the given value as JSON to the http.ResponseWriter with the specified status code. If there is an error encoding the value to JSON, it returns the error but does not write an error response to the client, as this function is intended to be used for writing successful responses. The caller should handle writing error responses separately if needed.
Types ¶
type ActionGroup ¶
type ClientConfig ¶
type ClientConfig struct {
URL string `json:"url,omitempty"`
Token string `json:"token,omitempty"`
Timeout time.Duration `json:"timeout,omitzero"`
TLS struct {
SkipVerify bool `json:"skip-verify,omitzero"`
CACerts []byte `json:"ca-certs,omitempty"`
} `json:"tls"`
Trace bool `json:"trace,omitempty"`
}
ClientConfig represents the configuration for creating a new IMS client.
type ContextKey ¶
type ContextKey string
const ( ContextKeyConfig ContextKey = "config" // Context key for passing configuration to handlers, type is *config.Config ContextKeyResponse ContextKey = "response" // Context key for passing response to handlers, type is *ims.Response )
type Endpoint ¶
type Endpoint struct {
Method string // HTTP method (e.g. "POST", "GET")
Path string // URL path (e.g. "/create", "/update") relative to application base path and including any path parameters (e.g. "/create/{id}")
Handler http.HandlerFunc
}
Endpoint represents an API endpoint for the IMS integration, including the HTTP method, path, and handler function.
type LogTransport ¶
type LogTransport struct {
Transport http.RoundTripper
}
LogTransport is a transport for tracing HTTP requests and responses.
type Response ¶
type Response struct {
StartTime time.Time `json:"start_time,omitzero"` // time the request was received by the gateway
EndTime time.Time `json:"end_time,omitzero"` // time the response is sent by the gateway
Duration time.Duration `json:"duration,omitzero"` // duration of processing the request
Status string `json:"status,omitempty"` // as per http.Response.Status from remote IMS, empty if request failed before reaching IMS
StatusCode int `json:"status_code,omitempty"` // as per http.Response.StatusCode from remote IMS, empty if request failed before reaching IMS
Error string `json:"error,omitempty"` // error message if applicable
ResultDetail string `json:"result_detail,omitempty"` // error or success detail if applicable
Action string `json:"action,omitempty"` // action taken by the gateway, e.g. "Created", "Updated", "Ignored", etc.
ID string `json:"id,omitempty"` // ID of created or updated incident if applicable
Data []string `json:"data,omitempty"` // any additional data returned by the gateway, e.g. for query results
DataTable [][]string `json:"data_table,omitempty"` // table of data, if applicable. first row is column names, subsequent rows are values
RawResponse any `json:"raw_response,omitempty"`
}
Response is the standard response from the IMS gateway, which may include the status code and message from the gateway itself, as well as any data returned by the gateway and the ID of the created or updated incident if applicable. The ProxyResponse field can be used to include the raw response from the proxy for debugging or logging purposes.
type Results ¶
Results represents the results of an IMS query, which is a slice of maps of string key/value pairs representing the fields and values of each result. This is used for returning query results from the IMS gateway to the client.
type SnowResult ¶
type SnowResult struct {
Results Results `json:"result,omitempty"`
Error struct {
Message string `json:"message"`
Detail string `json:"detail"`
} `json:"error"`
Status string `json:"status,omitempty"`
}
SnowResult is the response from ServiceNow. It contains the results of the request, which is a slice of results. It also contains an error message if the request failed. The status field is used to indicate the status of the request. If the request was successful, the status will be "success". If the request failed, the status will be "error". The error field contains the error message and detail if the request failed. The results field contains the results of the request.
type SnowResultsResponse ¶
type Transformation ¶ added in v1.28.0
type Transformation struct {
Defaults map[string]string `mapstructure:"defaults,omitempty"`
Remove []string `mapstructure:"remove,omitempty"`
Rename map[string]string `mapstructure:"rename,omitempty"`
MustInclude []string `mapstructure:"must-include,omitempty"`
Include []string `mapstructure:"include,omitempty"`
Exclude []string `mapstructure:"exclude,omitempty"`
}
func (Transformation) Transform ¶ added in v1.28.0
func (s Transformation) Transform(cf *config.Config, idp string, input map[string]string) (output map[string]string, err error)
Transform applies the Transformation to the given input incident fields and values and returns output. It returns an error if the transformation was not successful and output should not be used
Transformation is applied in the following order:
1. Defaults: For each key/value pair in the `Defaults` map, if the key is not already present in the incident or if the value is empty, the value from the `Defaults` map is added to the incident. The value from the `Defaults` map is expanded using the configuration values in cf, which allows for dynamic values.
2. Remove: For each key in the `Remove` slice, if the key is present in the incident, it is removed from the incident. It is not necessary to include double-underscored (e.g. `__field`) prefixed field names as these are always removed after applying the other stages of the transformation, and in many cases should not be included as they are used in later stages like Rename and MustInclude.
3. Rename:
a. Each input field with the prefix `__IDPNAME_` is renamed to the same name without the prefix. For example, `__IDPNAME_short_description` would be renamed to `short_description`. This allows for fields that are meant to be preserved during renaming to be retained, as they will not be deleted after renaming.
b. For each key/value pair in the `Rename` map, if the key is present in the incident, it is renamed to the value specified in the `Rename` map. If a field is renamed from a name that starts with `__` to a name that does not start with `__`, it will not be deleted after renaming. This allows for fields that are meant to be preserved during renaming to be retained.
4. Exclude: If the `Exclude` slice is not empty, any keys in the incident that do not match any of the regular expressions in the `Exclude` slice are removed from the incident. This allows for filtering out any fields that are not explicitly allowed by the regular expressions in the `Exclude` slice. The regular expressions supported are in Go regexp/syntax(https://pkg.go.dev/regexp/syntax) syntax. If the Exclude slice is empty, no fields are excluded at this stage.
5. Include: If the `Include` slice is not empty, only keys in the incident that match at least one of the regular expressions in the `Include` slice are retained in the incident. This allows for filtering out any fields that are not explicitly allowed by the regular expressions in the `Include` slice. The regular expressions supported are in Go regexp/syntax(https://pkg.go.dev/regexp/syntax) syntax. If the Include slice is empty, all fields are included at this stage.
6. MustInclude: For each key in the `MustInclude` slice, if the key is not present in the incident after applying the previous transformations, an error is returned indicating that a required field is missing. The transformation process is halted at this point if any required fields are missing.
7. Finally, any keys in the incident that start with `__` are removed from the incident, as these are considered internal fields that should not be sent to the remote IMS.