base

package module
v1.15.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 9, 2021 License: MIT Imports: 16 Imported by: 21

Documentation

Overview

This package contains shared utility functions for HMS Go code.

HMS Type and Component Definitions

These are functions that define common types that are used to describe HMS component data that represents system components and valid values for that data.

HMS Errors and RFC 7807 ProblemDetails RFC 7807 ProblemDetails">¶

These are common methods for defining a custom HMS error type and producing RFC 7807-compliant ProblemDetails payloads for reporting problems that occur during HMS API calls.

Index

Constants

View Source
const HMSErrorUnsetDefault = "no error message or class set"
View Source
const (
	MaxNodesInEnclosure = 8
)
View Source
const ProblemDetailContentType = "application/problem+json"
View Source
const ProblemDetailsHTTPStatusType = "about:blank"
View Source
const USERAGENT = "User-Agent"

Variables

View Source
var ErrHMSNeedForce = e.NewChild("operation not allowed and not forced.")
View Source
var ErrHMSStateInvalid = e.NewChild("was not a valid HMS state")
View Source
var ErrHMSStateUnsupported = e.NewChild("HMSState value not supported for this operation")
View Source
var ErrHMSTypeInvalid = e.NewChild("got HMSTypeInvalid instead of valid type")
View Source
var ErrHMSTypeUnsupported = e.NewChild("HMSType value not supported for this operation")
View Source
var JStatString = map[JobStatus]string{
	JSTAT_DEFAULT:    "JSTAT_DEFAULT",
	JSTAT_QUEUED:     "JSTAT_QUEUED",
	JSTAT_PROCESSING: "JSTAT_PROCESSING",
	JSTAT_COMPLETE:   "JSTAT_COMPLETE",
	JSTAT_CANCELLED:  "JSTAT_CANCELLED",
	JSTAT_ERROR:      "JSTAT_ERROR",
	JSTAT_MAX:        "JSTAT_MAX",
}

Functions

func ControllerHasChassis

func ControllerHasChassis(hmsType HMSType) bool

Normally every controller should has 1+ Chassis, but certain special types may not, and we don't use them if even if they are there.

func ControllerHasChassisStr

func ControllerHasChassisStr(hmsTypeStr string) bool

String version of above.

func ControllerHasSystems

func ControllerHasSystems(hmsType HMSType) bool

Returns whether hmsType does not expect System collections to be present, or if so, non-empty.

func ControllerHasSystemsStr

func ControllerHasSystemsStr(hmsTypeStr string) bool

String version of above.

func GetHMSArchList

func GetHMSArchList() []string

Get a list of all valid HMS Arch

func GetHMSClassList

func GetHMSClassList() []string

Get a list of all valid HMS Class

func GetHMSCompParent

func GetHMSCompParent(xname string) string

Given a properly formatted xname, get its immediate parent.

i.e. x0c0s22b11 would become x0c0s22

func GetHMSFlagList

func GetHMSFlagList() []string

Get a list of all valid HMS flags

func GetHMSNetTypeList

func GetHMSNetTypeList() []string

Get a list of all valid HMS NetTypes

func GetHMSRoleList

func GetHMSRoleList() []string

Get a list of all valid HMS roles

func GetHMSStateList

func GetHMSStateList() []string

func GetHMSSubRoleList

func GetHMSSubRoleList() []string

Get a list of all valid HMS subroles

func GetHMSTypeList

func GetHMSTypeList() []string

func GetHMSTypeString

func GetHMSTypeString(xname string) string

Get the HMSType for a given xname, based on its pattern in the recognition table above (string version). If no type matches, the empty string is returned.

func GetServiceInstanceName

func GetServiceInstanceName() (string, error)

func GetValidStartStateWForce

func GetValidStartStateWForce(
	afterState string,
	force bool,
) (beforeStates []string, err error)

Same as above, but with force flag. If not found, returns ErrHMSStateInvalid. If can only be forced, and force = false, error will be ErrHMSNeedForce. Otherwise list of starting states. If force = true and no errors, an empty array means no restrictions.

func GetValidStartStates

func GetValidStartStates(afterState string) (beforeStates []string, ok bool)

If ok == true, beforeStates contain valid current states a component can be in if it is being transitioned to afterState without being forced (either because it is a bad idea, or the state should only be set by HSM and not by other software). An empty array means 'None without force=true

If ok == false, afterState matched no valid HMS State (case insensitive)

func InitTypes

func InitTypes(configpath string) error

main

func IsAlphaNum

func IsAlphaNum(s string) bool

Returns true if s is alphanumeric only (only letters and numbers, no punctuation or spaces.

func IsHMSCompIDValid

func IsHMSCompIDValid(xname string) bool

Returns true if xname is valid, i.e. matches some format for a valid HMS component type. False if it is invalid.

func IsHMSError

func IsHMSError(err error) bool

See if an error (some thing implementing Error() interface is an HMSError

Returns 'true' if err is HMSError Returns 'false' if err is something else that implements Error()

func IsHMSErrorClass

func IsHMSErrorClass(err error, class string) bool

Returns false if 'err' is not an HMSError, or, if it is, if 'class' doesn't match the HMSError's Class field.

func IsHMSErrorClassIgnCase

func IsHMSErrorClassIgnCase(err error, class string) bool

Returns false if 'err' is not an HMSError, or, if it is, if 'class' doesn't match the HMSError's Class field (case insensitive).

func IsHMSTypeContainer

func IsHMSTypeContainer(hmsType HMSType) bool

Returns whether hmsType is a container type, i.e. that contains other components but is not a logical type (i.e. Node, that may or may not be a discrete hardware module), or a specialized terminal subcomponent (HSNAsic, Processor, etc.)

NOTE: This is used specifically for Redfish "Chassis" components. so non-Chassis (e.g. PDUs) don't apply (different type, outlets are not really separate physical pieces)

func IsHMSTypeController

func IsHMSTypeController(hmsType HMSType) bool

Returns whether hmsType is a controller type, i.e. that would host a Redfish entry point

func IsHMSTypeStrContainer

func IsHMSTypeStrContainer(hmsTypeStr string) bool

Returns whether hmsTypeStr matches a container type, i.e. that contains other components but is not a logical type (i.e. Node, that may or may not be a discrete hardware module), or a specialized terminal subcomponent (HSNAsic, Processor, etc.)

func IsHMSTypeStrController

func IsHMSTypeStrController(hmsTypeStr string) bool

Returns whether hmsTypeStr matches a controller type, i.e. that would host a Redfish entry point

func IsNumeric

func IsNumeric(s string) bool

Returns true if s is numeric only (only numbers, no letters, punctuation or spaces.

func IsPostBootState

func IsPostBootState(stateStr string) bool

Check to see if the state is above on (on is the highest we will get from Redfish, so these are state set by higher software layers)

func NormalizeHMSCompID

func NormalizeHMSCompID(xname string) string

This lower-cases the xname id does other normalization so we always represent the same location with the same string. NOTE: this does not validate the xname, so do not use it to see if it is valid. However, any string post normalization should still be as invalid or valid as an xname as it was prior to this call.

func RemoveLeadingZeros

func RemoveLeadingZeros(s string) string

Remove leading zeros, i.e. for each run of numbers, trim off leading zeros so each run starts with either non-zero, or is a single zero.

func SendProblemDetails

func SendProblemDetails(w http.ResponseWriter, p *ProblemDetails, status int) error

Send specially-coded RFC7807 Problem Details response. A set ProblemDetails struct is expected ('p') and should always contain at least Type to conform to the spec (we will always print the Type field, but it would contain the empty string if unset which isn't technically valid for the spec.

The HTTP status code in the header is set to the 'status' arg if it is NON-zero. If 'status' = 0, then 'p'.Status will be used. If that is unset (i.e. 0) also, we will use a default error code of 400.

For example:

p := base.NewProblemDetails(
    "https://example.com/probs/MyProblem",
    "My Problem's Title",
    "Detail for this problem",
    "/instances/myprob/1",
    http.StatusConflict)  // 409
...
if err != nil {
   base.SendProblemDetails(w, p, 0)
   return
}

...will include the following in the response header:

HTTP/1.1 409 Conflict
Content-Type: application/problem+json

With the following body:

{
   "Type": "https://example.com/probs/MyProblem",
   "Title": "My Problem's Title",
   "Detail": "Detail for this problem",
   "Instance": "/instances/myprob/1",
   "Status": 409
}

func SendProblemDetailsGeneric

func SendProblemDetailsGeneric(w http.ResponseWriter, status int, msg string) error

Generate and then send a generic RFC 7807 problem response based on a HTTP status code ('status') and a message string ('msg'). This generates a generic title and type based on the HTTP 'status' code. The ProblemDetails "Detail" field is filled in using 'msg'.

If you are already returning just a simple error message and want an easy way to convert this into a basic (but valid) RFC7807 ProblemDetails, this is almost a drop-in replacement.

// If request was for a component that is not in DB, send RFC 7807
// ProblemDetails and exit HTTP handler
err := GetComponentFromDB(component_from_query)
if err != nil {
   base.SendProblemDetailsGeneric(w, http.StatusNotFound, "No such component")
   return
}

The above will include the following in the response header:

HTTP/1.1 404 Not Found
Content-Type: application/problem+json

With the following body:

{
   "Type": "about:blank",
   "Title": "Not Found",
   "Detail": "No such component",
   "Status": 404
}

func SetHTTPUserAgent

func SetHTTPUserAgent(req *http.Request, instName string)

func ValidateCompIDs

func ValidateCompIDs(compIDs []string, dupsValid bool) ([]string, []string)

ValidateCompIDs validates an array of component IDs (xnames) into valid and invalid arrays optionally adding duplicates to the invalid array or discarding them.

func VerifyNormalizeArch

func VerifyNormalizeArch(archStr string) string

Returns the given arch string (adjusting any capitalization differences), if a valid arch was given. Else, return the empty string.

func VerifyNormalizeClass

func VerifyNormalizeClass(classStr string) string

Returns the given class string (adjusting any capitalization differences), if a valid class was given. Else, return the empty string.

func VerifyNormalizeCompID

func VerifyNormalizeCompID(idStr string) string

Returns the given xname ID string (adjusting for any capitalization and whitespace and leading zero differences) if a valid xname was given. Else, return the empty string.

func VerifyNormalizeFlag

func VerifyNormalizeFlag(flagStr string) string

Returns the given flag string (adjusting any capitalization differences), if a valid flag was given. Else, return the empty string.

func VerifyNormalizeFlagOK

func VerifyNormalizeFlagOK(flag string) string

As above, but if flag is the empty string, then return FlagOK. If non-empty and invalid, return the empty string.

func VerifyNormalizeNetType

func VerifyNormalizeNetType(netTypeStr string) string

Returns the given net type string (adjusting any capitalization differences), if a valid netType was given. Else, return the empty string.

func VerifyNormalizeRole

func VerifyNormalizeRole(roleStr string) string

Returns the given role string (adjusting any capitalization differences), if a valid role was given. Else, return the empty string.

func VerifyNormalizeState

func VerifyNormalizeState(stateStr string) string

Returns the given state string (adjusting any capitalization differences), if a valid state is given. Else, return the empty string.

func VerifyNormalizeSubRole

func VerifyNormalizeSubRole(subRoleStr string) string

Returns the given SubRole string (adjusting any capitalization differences), if a valid SubRole was given. Else, return the empty string.

func VerifyNormalizeType

func VerifyNormalizeType(typeStr string) string

Returns the given HMS type string (adjusting any capitalization differences), if a valid HMS component type was given. Else, return the empty string.

Types

type Auth

type Auth struct {
	Username string
	Password string
}

HTTP basic authentication structure.

func (Auth) String

func (auth Auth) String() string

Custom String function to prevent passwords from being printed directly (accidentally) to output.

type Component

type Component struct {
	ID                  string      `json:"ID"`
	Type                string      `json:"Type"`
	State               string      `json:"State,omitempty"`
	Flag                string      `json:"Flag,omitempty"`
	Enabled             *bool       `json:"Enabled,omitempty"`
	SwStatus            string      `json:"SoftwareStatus,omitempty"`
	Role                string      `json:"Role,omitempty"`
	SubRole             string      `json:"SubRole,omitempty"`
	NID                 json.Number `json:"NID,omitempty"`
	Subtype             string      `json:"Subtype,omitempty"`
	NetType             string      `json:"NetType,omitempty"`
	Arch                string      `json:"Arch,omitempty"`
	Class               string      `json:"Class,omitempty"`
	ReservationDisabled bool        `json:"ReservationDisabled,omitempty"`
	Locked              bool        `json:"Locked,omitempty"`
}

This is the equivalent to rs_node_t in Cascade. It is the minimal amount of of information for tracking component state and other vital info at an abstract level. The hwinv is for component-type specific fields and detailed HW attributes, i.e. just like XC.

For most HMS operations (and non-inventory ones in the managed plane) this info should be sufficient. We want to keep it minimal for speed. Those fields that are not fixed at discovery should be those that can change outside of discovery in response to system activity, i.e. hwinv should contain only fields that are basically static between discoveries of the endpoint. Things like firmware versions might be an exception, but that would be a separate process SM would

1.0.0

type ComponentArray

type ComponentArray struct {
	Components []*Component `json:"Components"`
}

A collection of 0-n Components. It could just be an ordinary array but we want to save the option to have indentifying info, etc. packaged with it, e.g. the query parameters or options that produced it, especially if there are fewer fields than normal being included.

type HMSArch

type HMSArch string
const (
	ArchX86     HMSArch = "X86"
	ArchARM     HMSArch = "ARM"
	ArchUnknown HMSArch = "UNKNOWN"
	ArchOther   HMSArch = "Other"
)

func (HMSArch) String

func (r HMSArch) String() string

Allow HMSArch to be treated as a standard string type.

type HMSClass

type HMSClass string
const (
	ClassRiver    HMSClass = "River"
	ClassMountain HMSClass = "Mountain"
	ClassHill     HMSClass = "Hill"
)

func (HMSClass) String

func (r HMSClass) String() string

Allow HMSClass to be treated as a standard string type.

type HMSError

type HMSError struct {
	// Used to identify similar groups of errors to higher-level software.
	Class string `json:"class"`

	// Message, used as error string for Error()
	Message string `json:"message"`

	// Optional full ProblemDetails
	Problem *ProblemDetails `json:"problem,omitempty"`
}

Custom Go 'error' type for HMS - Implements Error()

Works like a standard Go 'error', but can be distinguished as an HMS-specific error with an optional class for better handling upstream. An RFC7807 error can optionally be added in case we need to pass those through multiple layers- but without forcing us to (since they still look like regular Go errors). Note that this is just a starting point. We can attach other types of info later if we want.

Part of the motivation is so we can determine which errors are safe to return to users, i.e. we don't want to give them things that expose details about the database structure.

Can attach custom RFC7807 response if needed.

func GetHMSError

func GetHMSError(err error) (*HMSError, bool)

Test and retrieve HMSError info, if error is in fact of that type.

If bool is 'true', HMSError will be a non-nil HMSError with the expected extended HMSError fields.

If bool is 'false', err is not an HMSError and *HMSError will be nil

func NewHMSError

func NewHMSError(class, msg string) *HMSError

New HMSError, with message string and optional class.

A subsequent call to AddProblem() can associate a ProblemDetails with it. By default Problem pointer is nil (again, this is optional functionality)

func (*HMSError) AddProblem

func (e *HMSError) AddProblem(p *ProblemDetails)

Add an ProblemDetails to be associated with e

Note: This simply associates the pointer to p with e. There is no new ProblemDetails created and no deep copy is performed.

func (*HMSError) Error

func (e *HMSError) Error() string

Implement Error() interface - This makes it so an HMSError can be returned anywhere an ordinary Go 'error' is returned.

The receiver of an 'error' can then use one of the IsHMSError* or HasHMSError functions to test if it is an HMSError, and if so, to obtain the additional fields.

func (*HMSError) GetProblem

func (e *HMSError) GetProblem() *ProblemDetails

If e has a ProblemDetails associated with it, return a pointer to it If not, return nil.

func (*HMSError) IsClass

func (e *HMSError) IsClass(class string) bool

Return true if 'class' exactly matches Class field for HMSError

func (*HMSError) IsClassIgnCase

func (e *HMSError) IsClassIgnCase(class string) bool

Return true if 'class' matches Class field for HMSError (case insensitive)

func (*HMSError) NewChild

func (e *HMSError) NewChild(msg string) *HMSError

Create a new HMSError that is a copy of e, except with an updated "Message" field if 'msg' is not the empty string. Conversely, if 'msg' IS the empty string, i.e. "", the operation is equivalent to a copy.

Note: This DOES NOT COPY ProblemDetails if added with AddProblem. Instead, use NewChildWithProblem() for cases like this (or if you're unsure).

The (newerr).Problem pointer is always set to nil with this function.

func (*HMSError) NewChildWithProblem

func (e *HMSError) NewChildWithProblem(msg, instance string) *HMSError

Create a newly-allocated child HMSError, deep-copying the parent, including any ProblemDetails that (may) have been associated using AddProblem().

In addition to copying, the 'msg' arg (if non-empty) is used to overwrite HMSError's "Message" and (if ProblemDetails are present) the ProblemDetails "Detail" field is also set to the same string.

The ProblemDetails 'Instance' is also updated if the 'instance' arg is a non-empty string.

If both 'msg' and 'instance' are unset the result is effectively a simple (deep) copy of e (including a deep copy of e.Problem).

This method basically combines the functionality of both the HMSError and ProblemDetails NewChild() functions.

type HMSFlag

type HMSFlag string
const (
	FlagUnknown HMSFlag = "Unknown"
	FlagOK      HMSFlag = "OK"      // Functioning properly
	FlagWarning HMSFlag = "Warning" // Continues to operate, but has an issue that may require attention.
	FlagAlert   HMSFlag = "Alert"   // No longer operating as expected.  The state may also have changed due to error.
	FlagLocked  HMSFlag = "Locked"  // Another service has reserved this component.
)

Valid flag values.

func (HMSFlag) String

func (f HMSFlag) String() string

Allow HMSFlag to be treated as a standard string type.

type HMSNetType

type HMSNetType string
const (
	NetSling      HMSNetType = "Sling"
	NetInfiniband HMSNetType = "Infiniband"
	NetEthernet   HMSNetType = "Ethernet"
	NetOEM        HMSNetType = "OEM" // Placeholder for non-slingshot
	NetNone       HMSNetType = "None"
)

func (HMSNetType) String

func (r HMSNetType) String() string

Allow HMSNetType to be treated as a standard string type.

type HMSRole

type HMSRole string
const (
	RoleCompute     HMSRole = "Compute"
	RoleService     HMSRole = "Service"
	RoleSystem      HMSRole = "System"
	RoleApplication HMSRole = "Application"
	RoleStorage     HMSRole = "Storage"
	RoleManagement  HMSRole = "Management"
)

Valid role values.

func (HMSRole) String

func (r HMSRole) String() string

Allow HMSRole to be treated as a standard string type.

type HMSState

type HMSState string

State field used in component, set in response to events by state manager. 1.0.0

const (
	StateUnknown   HMSState = "Unknown"   // The State is unknown.  Appears missing but has not been confirmed as empty.
	StateEmpty     HMSState = "Empty"     // The location is not populated with a component
	StatePopulated HMSState = "Populated" // Present (not empty), but no further track can or is being done.
	StateOff       HMSState = "Off"       // Present but powered off
	StateOn        HMSState = "On"        // Powered on.  If no heartbeat mechanism is available, it's software state may be unknown.

	StateStandby HMSState = "Standby" // No longer Ready and presumed dead.  It typically means HB has been lost (w/alert).
	StateHalt    HMSState = "Halt"    // No longer Ready and halted.  OS has been gracefully shutdown or panicked (w/ alert).
	StateReady   HMSState = "Ready"   // Both On and Ready to provide its expected services, i.e. used for jobs.

)

Valid state values for components - should refect hardware state Enabled/Disabled is a separate boolean field, as the component should still have it's actual physical state known and tracked at all times, so we know what it is when it is enabled. It also avoids the primary case where admins need to modify the state field manually.

NOTE: there will be no state between on and ready. If the managed plane software does not have heartbeats, On is as high as it will ever get. So "active" is not useful. 'Paused' is not in scope now that the software status field exists.

func (HMSState) String

func (s HMSState) String() string

Allow HMSState to be treated as a standard string type.

type HMSSubRole

type HMSSubRole string
const (
	SubRoleMaster  HMSSubRole = "Master"
	SubRoleWorker  HMSSubRole = "Worker"
	SubRoleStorage HMSSubRole = "Storage"
)

Valid SubRole values.

func (HMSSubRole) String

func (r HMSSubRole) String() string

Allow HMSSubRole to be treated as a standard string type.

type HMSType

type HMSType string
const (
	CDU                      HMSType = "CDU"                      // dD
	CDUMgmtSwitch            HMSType = "CDUMgmtSwitch"            // dDwW
	CabinetCDU               HMSType = "CabinetCDU"               // xXdD
	Cabinet                  HMSType = "Cabinet"                  // xX
	CabinetBMC               HMSType = "CabinetBMC"               // xXbB
	CabinetPDUController     HMSType = "CabinetPDUController"     // xXmM
	CabinetPDU               HMSType = "CabinetPDU"               // xXmMpP
	CabinetPDUNic            HMSType = "CabinetPDUNic"            // xXmMiI
	CabinetPDUOutlet         HMSType = "CabinetPDUOutlet"         // xXmMpPjJ DEPRECATED
	CabinetPDUPowerConnector HMSType = "CabinetPDUPowerConnector" // xXmMpPvV

	Chassis                  HMSType = "Chassis"                  // xXcC
	ChassisBMC               HMSType = "ChassisBMC"               // xXcCbB
	ChassisBMCNic            HMSType = "ChassisBMCNic"            // xXcCbBiI
	CMMRectifier             HMSType = "CMMRectifier"             // xXcCtT
	CMMFpga                  HMSType = "CMMFpga"                  // xXcCfF
	CEC                      HMSType = "CEC"                      // xXeE
	ComputeModule            HMSType = "ComputeModule"            // xXcCsS
	RouterModule             HMSType = "RouterModule"             // xXcCrR
	NodeBMC                  HMSType = "NodeBMC"                  // xXcCsSbB
	NodeBMCNic               HMSType = "NodeBMCNic"               // xXcCsSbBiI
	NodeEnclosure            HMSType = "NodeEnclosure"            // xXcCsSeE
	NodeEnclosurePowerSupply HMSType = "NodeEnclosurePowerSupply" // xXcCsSeEtT
	NodePowerConnector       HMSType = "NodePowerConnector"       // xXcCsSjJ
	Node                     HMSType = "Node"                     // xXcCsSbBnN
	Processor                HMSType = "Processor"                // xXcCsSbBnNpP
	StorageGroup             HMSType = "StorageGroup"             // xXcCsSbBnNgG
	Drive                    HMSType = "Drive"                    // xXcCsSbBnNgGkK
	NodeNic                  HMSType = "NodeNic"                  // xXcCsSbBnNiI
	NodeHsnNic               HMSType = "NodeHsnNic"               // xXcCsSbBnNhH
	Memory                   HMSType = "Memory"                   // xXcCsSbBnNdD
	NodeAccel                HMSType = "NodeAccel"                // xXcCsSbBnNaA
	NodeAccelRiser           HMSType = "NodeAccelRiser"           // xXcCsSbBnNrR
	NodeFpga                 HMSType = "NodeFpga"                 // xXcCsSbBfF
	HSNAsic                  HMSType = "HSNAsic"                  // xXcCrRaA
	RouterFpga               HMSType = "RouterFpga"               // xXcCrRfF
	RouterTORFpga            HMSType = "RouterTORFpga"            // xXcCrRtTfF
	RouterBMC                HMSType = "RouterBMC"                // xXcCrRbB
	RouterBMCNic             HMSType = "RouterBMCNic"             // xXcCrRbBiI
	RouterPowerConnector     HMSType = "RouterPowerConnector"     // xXcCrRvV

	HSNBoard            HMSType = "HSNBoard"            // xXcCrReE
	HSNLink             HMSType = "HSNLink"             // xXcCrRaAlL
	HSNConnector        HMSType = "HSNConnector"        // xXcCrRjJ
	HSNConnectorPort    HMSType = "HSNConnectorPort"    // xXcCrRjJpP
	MgmtSwitch          HMSType = "MgmtSwitch"          // xXcCwW
	MgmtHLSwitch        HMSType = "MgmtHLSwitch"        // xXcChHsS
	MgmtSwitchConnector HMSType = "MgmtSwitchConnector" // xXcCwWjJ

	// Special types and wildcards
	SMSBox         HMSType = "SMSBox"    // smsN
	Partition      HMSType = "Partition" // pH.S
	System         HMSType = "System"    // s0
	HMSTypeAll     HMSType = "All"       // all
	HMSTypeAllComp HMSType = "AllComp"   // all_comp
	HMSTypeAllSvc  HMSType = "AllSvc"    // all_svc
	HMSTypeInvalid HMSType = "INVALID"   // Not a valid type/xname
)

This is an enum (though they have no numeric values in ReST and we don't want to store them that way since we could get bit by renumbering. the down-side is that we will have to normalize capitalization differences. This isn't a huge problem since the type field should only be modified by discovery. It shouldn't be changed by the user, since it must map to a corresponding cname and we can't change its hierarchical relationship.

func GetHMSType

func GetHMSType(xname string) HMSType

Get the HMSType for a given xname, based on its pattern in the recognition table above. If no string matches, HMSTypeInvalid is returned.

func ToHMSType

func ToHMSType(typeStr string) HMSType

Returns the given HMSType (adjusting any capitalization differences), if a valid HMS component type string was given. Else, return HMSTypeINVALID.

func (HMSType) String

func (t HMSType) String() string

Allow HMSType to be treated as a standard string type.

type HTTPRequest

type HTTPRequest struct {
	Context            context.Context // Context to pass to the underlying HTTP client.
	FullURL            string          // The full URL to pass to the HTTP client.
	Method             string          // HTTP method to use.
	Payload            []byte          // Bytes payload to pass if desired of ContentType.
	Auth               *Auth           // Basic authentication if necessary using Auth struct.
	Timeout            time.Duration   // Timeout for entire transaction.
	SkipTLSVerify      bool            // Ignore TLS verification errors?
	ExpectedStatusCode int             // Expected HTTP status return code.
	ContentType        string          // HTTP content type of Payload.
}

Package to slightly abstract some of the most mundane of HTTP interactions. Primary intention is as a JSON getter and parser, with the latter being a generic interface that can be converted to a custom structure.

func NewHTTPRequest

func NewHTTPRequest(fullURL string) *HTTPRequest

NewHTTPRequest creates a new HTTPRequest with default settings.

func (*HTTPRequest) DoHTTPAction

func (request *HTTPRequest) DoHTTPAction() (payloadBytes []byte, err error)

Given a HTTPRequest this function will facilitate the desired operation using the retryablehttp package to gracefully retry should the connection fail.

func (*HTTPRequest) GetBodyForHTTPRequest

func (request *HTTPRequest) GetBodyForHTTPRequest() (v interface{}, err error)

Returns an interface for the response body for a given request by calling DoHTTPAction and unmarshaling. As such, do NOT call this method unless you expect a JSON body in return!

A powerful way to use this function is by feeding its result to the mapstructure package's Decode method:

v := request.GetBodyForHTTPRequest()
myTypeInterface := v.(map[string]interface{})
var myPopulatedStruct MyType
mapstructure.Decode(myTypeInterface, &myPopulatedStruct)

In this way you can generically make all your HTTP requests and essentially "cast" the resulting interface to a structure of your choosing using it as normal after that point. Just make sure to infer the correct type for `v`.

func (*HTTPRequest) String

func (request *HTTPRequest) String() string

type Job

type Job interface {
	Log(format string, a ...interface{})
	//New(t JobType)
	Type() JobType
	//JobSCN() JobSCN
	Run()
	GetStatus() (JobStatus, error)
	SetStatus(JobStatus, error) (JobStatus, error)
	Cancel() JobStatus
}

type JobStatus

type JobStatus int
const (
	JSTAT_DEFAULT    JobStatus = 0
	JSTAT_QUEUED     JobStatus = 1
	JSTAT_PROCESSING JobStatus = 2
	JSTAT_COMPLETE   JobStatus = 3
	JSTAT_CANCELLED  JobStatus = 4
	JSTAT_ERROR      JobStatus = 5
	JSTAT_MAX        JobStatus = 6
)

type JobType

type JobType int

type ProblemDetails

type ProblemDetails struct {
	Type     string `json:"type"` // either url or "about:blank"
	Title    string `json:"title,omitempty"`
	Detail   string `json:"detail,omitempty"`
	Instance string `json:"instance,omitempty"`
	Status   int    `json:"status,omitempty"`
}

RFC 7807 Problem Details

These are the officially-specified fields. The implementation is allowed to add new ones, but we'll stick with these for now. Almost all are optional, however, and blank fields are not encoded if they are the empty string (which is fine

The only required field is Type and is expected to be a URL that should describe the problem type when dereferenced. It's not intended to be a dead link, but I don't think clients are allowed to assume it's not, either. We don't implement a way of serving these URLs here, in any case. It's not obligatory to have a lot of different problem types, or even desirable if the client can just andling them all the same basic way.

The only non-URL that is allowed for Type is "about:blank", but only in the situation where the semantics of the problem can be understood okay as a basic HTTP error. In this case Title should be the official HTTP status code string, not something custom. You are free to put anything you want in Detail however, so if you already have an error function that returns an error string, you can easily convert it into one of these generic HTTP errors. In fact, we offer a shortcut to doing this.

If Type is a URL, Title should describe the problem type. If you are doing this, and not just using type:"about:blank" and the HTTP error, for the title, it should be because you have some kind of problem that needs, or could benefit from, special or more involved treatment that the URL describes when dereferenced.

Detail explains in a human readible way what happened when a specific problem occurred.

Instance is another URI describing a specific occurrence of a problem. So within a particular Type and Title (a general problem type) the Detail and Instance document a specific incident in which that problem occurred. Or at least that's the general idea.

Status is the numerical HTTP status code. It is optional, and if present, should match at least the intended HTTP code in the header, though this is not strictly required.

For more info, reading RFC 7807 would obviously be the authoritative source.

func NewProblemDetails

func NewProblemDetails(ptype, title, detail, instance string, status int) *ProblemDetails

New full ProblemDetails, will all fields specified. Type is the only required field, and if any of the other args are left as the empty string, the fields won't appear in the JSON output at all.

p := base.NewProblemDetails(
    "https://example.com/probs/MyProblem",
    "My Problem's Title",
    "Details for this problem",
    "/instances/myprob/1",
    http.StatusBadRequest,
)

func NewProblemDetailsStatus

func NewProblemDetailsStatus(detail string, status int) *ProblemDetails

New generic ProblemDetails for errors that are just based on the HTTP status code. Type and Title are filled in based on the status code.

There is no need for a URL in this case, as the Type is allowed to be "about:blank" if title is just the Status code text and there is no special handling needed beside the usual for that HTTP (error) StatusCode.

NOTE: Status should only be filled in using http.Status* instead of a literal number.

'status' will be treated as http.StatusBadRequest (400) if it does not match a valid http status code.

Example:

p := base.NewProblemDetailsStatus(http.StatusNotFound, "No such component")

Produces a struct p with the following fields

&ProblemDetails{
   Type: "about:blank",
   Title: "Not Found",
   Detail: "No such component",
   Status: 404,
}

func (*ProblemDetails) NewChild

func (p *ProblemDetails) NewChild(detail, instance string) *ProblemDetails

Create a new ProblemDetails struct copied from p with only detail and instance (optionally) updated. If either field is the empty string, it will not be updated and the parent values will be used.

The basic idea here is to be able to define a few prototype ProblemDetails with the Type and Title filled in (along with a default Detail and HTTP Status code, if desired), and then create a child copy when a problem actually occurs with the specific Detail and (optionally) instance URI filled in.

Example:

p := base.NewProblemDetails(
    "https://example.com/probs/MyProblem",
    "My Problem's Title",
    "Generic details for this problem type",
    "/instances/myprobs/",
    http.StatusBadRequest,
)

// Copy updates Detail and instance
pChild := p.NewChild("Specific details for this problem", "/instances/myprobs/1")

// Copy has updated Detail field only
// i.e. p.Instance == pChildDetailOnly.Instance
pChildDetailOnly := p.NewChild("Specific details for this problem", "")

// Strict copy only, new ProblemDetails has identical fields.
pCopy := p.NewChild("", "")

type Worker

type Worker struct {
	WorkerPool  chan chan Job
	JobChannel  chan Job
	StopChannel chan bool
}

///////////////////////////////////////////////////////////////////////////// Workers /////////////////////////////////////////////////////////////////////////////

func NewWorker

func NewWorker(workerPool chan chan Job) Worker

Create a new worker

func (Worker) Start

func (w Worker) Start()

Start a worker to start consuming Jobs

func (Worker) Stop

func (w Worker) Stop()

Send as stop signal to the worker

type WorkerPool

type WorkerPool struct {
	Workers     []Worker
	Pool        chan chan Job
	JobQueue    chan Job
	StopChannel chan bool
}

///////////////////////////////////////////////////////////////////////////// WorkerPool /////////////////////////////////////////////////////////////////////////////

func NewWorkerPool

func NewWorkerPool(maxWorkers, maxJobQueue int) *WorkerPool

Create a new pool of workers

func (*WorkerPool) Queue

func (p *WorkerPool) Queue(job Job) int

Queue a job. Returns 1 if the operation would block because the work queue is full.

func (*WorkerPool) Run

func (p *WorkerPool) Run()

Starts all of the workers and the job dispatcher

func (*WorkerPool) Stop

func (p *WorkerPool) Stop()

Command the dispatcher to stop itself and all workers

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL