Documentation ¶
Index ¶
- Constants
- Variables
- func Asset(name string) ([]byte, error)
- func AssetDir(name string) ([]string, error)
- func AssetInfo(name string) (os.FileInfo, error)
- func AssetNames() []string
- func MustAsset(name string) []byte
- func OptionInitDB(api *API) error
- func RestoreAsset(dir, name string) error
- func RestoreAssets(dir, name string) error
- type API
- func (api *API) AddApp(app *Application) (*Application, error)
- func (api *API) AddAppCloning(app *Application, sourceAppID string) (*Application, error)
- func (api *API) AddChannel(channel *Channel) (*Channel, error)
- func (api *API) AddCoreosAction(action *CoreosAction) (*CoreosAction, error)
- func (api *API) AddGroup(group *Group) (*Group, error)
- func (api *API) AddPackage(pkg *Package) (*Package, error)
- func (api *API) AddTeam(team *Team) (*Team, error)
- func (api *API) Close()
- func (api *API) DeleteApp(appID string) error
- func (api *API) DeleteChannel(channelID string) error
- func (api *API) DeleteGroup(groupID string) error
- func (api *API) DeletePackage(pkgID string) error
- func (api *API) GenerateUserSecret(username, password string) (string, error)
- func (api *API) GetActivity(teamID string, p ActivityQueryParams) ([]*Activity, error)
- func (api *API) GetApp(appID string) (*Application, error)
- func (api *API) GetApps(teamID string, page, perPage uint64) ([]*Application, error)
- func (api *API) GetChannel(channelID string) (*Channel, error)
- func (api *API) GetChannels(appID string, page, perPage uint64) ([]*Channel, error)
- func (api *API) GetCoreosAction(packageID string) (*CoreosAction, error)
- func (api *API) GetGroup(groupID string) (*Group, error)
- func (api *API) GetGroups(appID string, page, perPage uint64) ([]*Group, error)
- func (api *API) GetInstance(instanceID, appID string) (*Instance, error)
- func (api *API) GetInstanceStatusHistory(instanceID, appID, groupID string, limit uint64) ([]*InstanceStatusHistoryEntry, error)
- func (api *API) GetInstances(p InstancesQueryParams) ([]*Instance, error)
- func (api *API) GetPackage(pkgID string) (*Package, error)
- func (api *API) GetPackageByVersion(appID, version string) (*Package, error)
- func (api *API) GetPackages(appID string, page, perPage uint64) ([]*Package, error)
- func (api *API) GetUpdatePackage(instanceID, instanceIP, instanceVersion, appID, groupID string) (*Package, error)
- func (api *API) GetUser(username string) (*User, error)
- func (api *API) RegisterEvent(instanceID, appID, groupID string, etype, eresult int, ...) error
- func (api *API) RegisterInstance(instanceID, instanceIP, instanceVersion, appID, groupID string) (*Instance, error)
- func (api *API) UpdateApp(app *Application) error
- func (api *API) UpdateChannel(channel *Channel) error
- func (api *API) UpdateGroup(group *Group) error
- func (api *API) UpdatePackage(pkg *Package) error
- func (api *API) UpdateUserPassword(username, newPassword string) error
- type Activity
- type ActivityQueryParams
- type Application
- type Channel
- type CoreosAction
- type Event
- type Group
- type Instance
- type InstanceApplication
- type InstanceStatusHistoryEntry
- type InstancesQueryParams
- type InstancesStatusStats
- type Package
- type Team
- type UpdatesStats
- type User
- type VersionBreakdownEntry
Constants ¶
const ( // EventUpdateComplete indicates that the update process completed. It could // mean a successful or failed updated, depending on the result attached to // the event. This applies to all events. EventUpdateComplete = 3 // EventUpdateDownloadStarted indicates that the instance started // downloading the update package. EventUpdateDownloadStarted = 13 // EventUpdateDownloadFinished indicates that the update package was // downloaded. EventUpdateDownloadFinished = 14 // EventUpdateInstalled indicates that the update package was installed. EventUpdateInstalled = 800 )
const ( // ResultFailed indicates that the operation associated with the event // posted failed. ResultFailed = 0 // ResultSuccess indicates that the operation associated with the event // posted succeeded. ResultSuccess = 1 // ResultSuccessReboot also indicates a successful operation, but it's // meant only to be used along with events of EventUpdateComplete type. // It's important that instances use EventUpdateComplete events in // combination with ResultSuccessReboot to communicate a successful update // completed as it has a special meaning for CoreRoller in order to adjust // properly the rollout policies and create activity entries. ResultSuccessReboot = 2 )
const ( // InstanceStatusUndefined indicates that the instance hasn't sent yet an // event to CoreRoller so it doesn't know in which state it is. InstanceStatusUndefined int = 1 + iota // InstanceStatusUpdateGranted indicates that the instance has been granted // an update (it should be reporting soon through events how is it going). InstanceStatusUpdateGranted // InstanceStatusError indicates that the instance reported an error while // processing the update. InstanceStatusError // InstanceStatusComplete indicates that the instance completed the update // process successfully. InstanceStatusComplete // InstanceStatusInstalled indicates that the instance has installed the // downloaded packages, but it hasn't applied it or restarted yet. InstanceStatusInstalled // InstanceStatusDownloaded indicates that the instance downloaded // successfully the update package. InstanceStatusDownloaded // InstanceStatusDownloading indicates that the instance started // downloading the update package. InstanceStatusDownloading // InstanceStatusOnHold indicates that the instance hasn't been granted an // update because one of the rollout policy limits has been reached. InstanceStatusOnHold )
const ( // PkgTypeCoreos indicates that the package is a CoreOS update package PkgTypeCoreos int = 1 + iota // PkgTypeDocker indicates that the package is a Docker container PkgTypeDocker // PkgTypeRocket indicates that the package is a Rocket container PkgTypeRocket // PkgTypeOther is the generic package type. PkgTypeOther )
const (
// Realm used for basic authentication.
Realm = "coreroller.org"
)
Variables ¶
var ( // ErrNoRowsAffected indicates that no rows were affected in an update or // delete database operation. ErrNoRowsAffected = errors.New("coreroller: no rows affected") // ErrInvalidSemver indicates that the provided semver version is not valid. ErrInvalidSemver = errors.New("coreroller: invalid semver") )
var ( // ErrInvalidPackage error indicates that a package doesn't belong to the // application it was supposed to belong to. ErrInvalidPackage = errors.New("coreroller: invalid package") // ErrBlacklistedChannel error indicates an attempt of creating/updating a // channel using a package that has blacklisted the channel. ErrBlacklistedChannel = errors.New("coreroller: blacklisted channel") )
var ( // ErrInvalidInstance indicates that the instance provided is not valid or // it doesn't exist. ErrInvalidInstance = errors.New("coreroller: invalid instance") // ErrInvalidApplicationOrGroup indicates that the application or group id // provided are not valid or related to each other. ErrInvalidApplicationOrGroup = errors.New("coreroller: invalid application or group") // ErrInvalidEventTypeOrResult indicates that the event or result provided // are not valid (CoreRoller only implements a subset of the Omaha protocol // events). ErrInvalidEventTypeOrResult = errors.New("coreroller: invalid event type or result") // ErrEventRegistrationFailed indicates that the event registration into // CoreRoller failed. ErrEventRegistrationFailed = errors.New("coreroller: event registration failed") // ErrNoUpdateInProgress indicates that an event was received but there // wasn't an update in progress for the provided instance/application, so // it was rejected. ErrNoUpdateInProgress = errors.New("coreroller: no update in progress") // ErrCoreosEventIgnored indicates that a CoreOS updater event was ignored. // This is a temporary solution to handle CoreOS specific behaviour. ErrCoreosEventIgnored = errors.New("coreroller: coreos event ignored") )
var ( // ErrInvalidChannel error indicates that a channel doesn't belong to the // application it was supposed to belong to. ErrInvalidChannel = errors.New("coreroller: invalid channel") // ErrExpectingValidTimezone error indicates that a valid timezone wasn't // provided when enabling the flag PolicyOfficeHours. ErrExpectingValidTimezone = errors.New("coreroller: expecting valid timezone") )
var ( // ErrRegisterInstanceFailed indicates that the instance registration did // not succeed. ErrRegisterInstanceFailed = errors.New("coreroller: register instance failed") // ErrUpdateInProgressOnInstance indicates that an update is currently in // progress on the instance requesting an update package, so the request // will be rejected. ErrUpdateInProgressOnInstance = errors.New("coreroller: update in progress on instance") // ErrNoPackageFound indicates that the group doesn't have a channel // assigned or that the channel doesn't have a package assigned. ErrNoPackageFound = errors.New("coreroller: no package found") // ErrNoUpdatePackageAvailable indicates that the instance requesting the // update has already the latest version of the application. ErrNoUpdatePackageAvailable = errors.New("coreroller: no update package available") // ErrUpdatesDisabled indicates that updates are not enabled in the group. ErrUpdatesDisabled = errors.New("coreroller: updates disabled") // ErrGetUpdatesStatsFailed indicates that there was a problem getting the // updates stats of the group which are needed to enforce the rollout // policy. ErrGetUpdatesStatsFailed = errors.New("coreroller: get updates stats failed") // ErrMaxUpdatesPerPeriodLimitReached indicates that the maximum number of // updates per period has been reached. ErrMaxUpdatesPerPeriodLimitReached = errors.New("coreroller: max updates per period limit reached") // ErrMaxConcurrentUpdatesLimitReached indicates that the maximum number of // concurrent updates has been reached. ErrMaxConcurrentUpdatesLimitReached = errors.New("coreroller: max concurrent updates limit reached") // ErrMaxTimedOutUpdatesLimitReached indicates that limit of instances that // timed out while updating has been reached. ErrMaxTimedOutUpdatesLimitReached = errors.New("coreroller: max timed out updates limit reached") // ErrGrantingUpdate indicates that something went wrong while granting an // update. ErrGrantingUpdate = errors.New("coreroller: error granting update") )
var ( // ErrBlacklistingChannel error indicates that the channel the package is // trying to blacklist is already pointing to the package. ErrBlacklistingChannel = errors.New("coreroller: channel trying to blacklist is already pointing to the package") )
var ( // ErrUpdatingPassword indicates that something went wrong while updating // the user's password. ErrUpdatingPassword = errors.New("coreroller: error updating password") )
Functions ¶
func Asset ¶
Asset loads and returns the asset for the given name. It returns an error if the asset could not be found or could not be loaded.
func AssetDir ¶
AssetDir returns the file names below a certain directory embedded in the file by go-bindata. For example if you run go-bindata on data/... and data contains the following hierarchy:
data/ foo.txt img/ a.png b.png
then AssetDir("data") would return []string{"foo.txt", "img"} AssetDir("data/img") would return []string{"a.png", "b.png"} AssetDir("foo.txt") and AssetDir("notexist") would return an error AssetDir("") will return []string{"data"}.
func AssetInfo ¶
AssetInfo loads and returns the asset info for the given name. It returns an error if the asset could not be found or could not be loaded.
func MustAsset ¶
MustAsset is like Asset but panics when Asset would return an error. It simplifies safe initialization of global variables.
func OptionInitDB ¶
OptionInitDB will initialize the database during the API instance creation, dropping all existing tables, which will force all migration scripts to be re-executed. Use with caution, this will DESTROY ALL YOUR DATA.
func RestoreAsset ¶
RestoreAsset restores an asset under the given directory
func RestoreAssets ¶
RestoreAssets restores an asset under the given directory recursively
Types ¶
type API ¶
type API struct {
// contains filtered or unexported fields
}
API represents an api instance used to interact with CoreRoller entities.
func New ¶
New creates a new API instance, creating the underlying db connection and applying db migrations available.
func (*API) AddApp ¶
func (api *API) AddApp(app *Application) (*Application, error)
AddApp registers the provided application.
func (*API) AddAppCloning ¶
func (api *API) AddAppCloning(app *Application, sourceAppID string) (*Application, error)
AddAppCloning registers the provided application, cloning the groups and channels from an existing application. Channels' packages will be set to null as packages won't be cloned.
func (*API) AddChannel ¶
AddChannel registers the provided channel.
func (*API) AddCoreosAction ¶
func (api *API) AddCoreosAction(action *CoreosAction) (*CoreosAction, error)
AddCoreosAction registers the provided Omaha CoreOS action.
func (*API) AddPackage ¶
AddPackage registers the provided package.
func (*API) DeleteChannel ¶
DeleteChannel removes the channel identified by the id provided.
func (*API) DeleteGroup ¶
DeleteGroup removes the group identified by the id provided.
func (*API) DeletePackage ¶
DeletePackage removes the package identified by the id provided.
func (*API) GenerateUserSecret ¶
GenerateUserSecret generates a md5 hash from the username and password provided (username:realm:password).
func (*API) GetActivity ¶
func (api *API) GetActivity(teamID string, p ActivityQueryParams) ([]*Activity, error)
GetActivity returns a list of activity entries that match the specified criteria in the query parameters.
func (*API) GetApp ¶
func (api *API) GetApp(appID string) (*Application, error)
GetApp returns the application identified by the id provided.
func (*API) GetApps ¶
func (api *API) GetApps(teamID string, page, perPage uint64) ([]*Application, error)
GetApps returns all applications that belong to the team id provided.
func (*API) GetChannel ¶
GetChannel returns the channel identified by the id provided.
func (*API) GetChannels ¶
GetChannels returns all channels associated to the application provided.
func (*API) GetCoreosAction ¶
func (api *API) GetCoreosAction(packageID string) (*CoreosAction, error)
GetCoreosAction returns the CoreOS action entry associated to the package id provided.
func (*API) GetInstance ¶
GetInstance returns the instance identified by the id provided.
func (*API) GetInstanceStatusHistory ¶
func (api *API) GetInstanceStatusHistory(instanceID, appID, groupID string, limit uint64) ([]*InstanceStatusHistoryEntry, error)
GetInstanceStatusHistory returns the status history of an instance in the context of the application/group provided.
func (*API) GetInstances ¶
func (api *API) GetInstances(p InstancesQueryParams) ([]*Instance, error)
GetInstances returns all instances that match with the provided criteria.
func (*API) GetPackage ¶
GetPackage returns the package identified by the id provided.
func (*API) GetPackageByVersion ¶
GetPackageByVersion returns the package identified by the application id and version provided.
func (*API) GetPackages ¶
GetPackages returns all packages associated to the application provided.
func (*API) GetUpdatePackage ¶
func (api *API) GetUpdatePackage(instanceID, instanceIP, instanceVersion, appID, groupID string) (*Package, error)
GetUpdatePackage returns an update package for the instance/application provided. The instance details and the application it's running will be registered in CoreRoller (or updated if it's already registered).
func (*API) RegisterEvent ¶
func (api *API) RegisterEvent(instanceID, appID, groupID string, etype, eresult int, previousVersion, errorCode string) error
RegisterEvent registers an event posted by an instance in CoreRoller. The event will be bound to an application/group combination.
func (*API) RegisterInstance ¶
func (api *API) RegisterInstance(instanceID, instanceIP, instanceVersion, appID, groupID string) (*Instance, error)
RegisterInstance registers an instance into CoreRoller.
func (*API) UpdateApp ¶
func (api *API) UpdateApp(app *Application) error
UpdateApp updates an existing application using the content of the application provided.
func (*API) UpdateChannel ¶
UpdateChannel updates an existing channel using the content of the channel provided.
func (*API) UpdateGroup ¶
UpdateGroup updates an existing group using the context of the group provided.
func (*API) UpdatePackage ¶
UpdatePackage updates an existing package using the content of the package provided.
func (*API) UpdateUserPassword ¶
UpdateUserPassword updates the password of the provided user.
type Activity ¶
type Activity struct { CreatedTs time.Time `db:"created_ts" json:"created_ts"` Class int `db:"class" json:"class"` Severity int `db:"severity" json:"severity"` Version string `db:"version" json:"version"` ApplicationName string `db:"application_name" json:"application_name"` GroupName dat.NullString `db:"group_name" json:"group_name"` ChannelName dat.NullString `db:"channel_name" json:"channel_name"` InstanceID dat.NullString `db:"instance_id" json:"instance_id"` }
Activity represents a CoreRoller activity entry.
type ActivityQueryParams ¶
type ActivityQueryParams struct { AppID string `db:"application_id"` GroupID string `db:"group_id"` ChannelID string `db:"channel_id"` InstanceID string `db:"instance_id"` Version string `db:"version"` Severity int `db:"severity"` Start time.Time `db:"start"` End time.Time `db:"end"` Page uint64 `json:"page"` PerPage uint64 `json:"perpage"` }
ActivityQueryParams represents a helper structure used to pass a set of parameters when querying activity entries.
type Application ¶
type Application struct { ID string `db:"id" json:"id"` Name string `db:"name" json:"name"` Description string `db:"description" json:"description"` CreatedTs time.Time `db:"created_ts" json:"created_ts"` TeamID string `db:"team_id" json:"-"` Groups []*Group `db:"groups" json:"groups"` Channels []*Channel `db:"channels" json:"channels"` Packages []*Package `db:"packages" json:"packages"` Instances struct { Count int `db:"count" json:"count"` } `db:"instances" json:"instances,omitempty"` }
Application represents a CoreRoller application instance.
type Channel ¶
type Channel struct { ID string `db:"id" json:"id"` Name string `db:"name" json:"name"` Color string `db:"color" json:"color"` CreatedTs time.Time `db:"created_ts" json:"created_ts"` ApplicationID string `db:"application_id" json:"application_id"` PackageID dat.NullString `db:"package_id" json:"package_id"` Package *Package `db:"package" json:"package"` }
Channel represents a CoreRoller application's channel.
type CoreosAction ¶
type CoreosAction struct { ID string `db:"id" json:"id"` Event string `db:"event" json:"event"` ChromeOSVersion string `db:"chromeos_version" json:"chromeos_version"` Sha256 string `db:"sha256" json:"sha256"` NeedsAdmin bool `db:"needs_admin" json:"needs_admin"` IsDelta bool `db:"is_delta" json:"is_delta"` DisablePayloadBackoff bool `db:"disable_payload_backoff" json:"disable_payload_backoff"` MetadataSignatureRsa string `db:"metadata_signature_rsa" json:"metadata_signature_rsa"` MetadataSize string `db:"metadata_size" json:"metadata_size"` Deadline string `db:"deadline" json:"deadline"` CreatedTs time.Time `db:"created_ts" json:"created_ts"` PackageID string `db:"package_id" json:"-"` }
CoreosAction represents an Omaha action with some CoreOS specific fields.
type Event ¶
type Event struct { ID int `db:"id" json:"id"` CreatedTs time.Time `db:"created_ts" json:"created_ts"` PreviousVersion dat.NullString `db:"previous_version" json:"previous_version"` ErrorCode dat.NullString `db:"error_code" json:"error_code"` InstanceID string `db:"instance_id" json:"instance_id"` ApplicationID string `db:"application_id" json:"application_id"` EventTypeID string `db:"event_type_id" json:"event_type_id"` }
Event represents an event posted by an instance to CoreRoller.
type Group ¶
type Group struct { ID string `db:"id" json:"id"` Name string `db:"name" json:"name"` Description string `db:"description" json:"description"` CreatedTs time.Time `db:"created_ts" json:"created_ts"` RolloutInProgress bool `db:"rollout_in_progress" json:"rollout_in_progress"` ApplicationID string `db:"application_id" json:"application_id"` ChannelID dat.NullString `db:"channel_id" json:"channel_id"` PolicyUpdatesEnabled bool `db:"policy_updates_enabled" json:"policy_updates_enabled"` PolicySafeMode bool `db:"policy_safe_mode" json:"policy_safe_mode"` PolicyOfficeHours bool `db:"policy_office_hours" json:"policy_office_hours"` PolicyTimezone dat.NullString `db:"policy_timezone" json:"policy_timezone"` PolicyPeriodInterval string `db:"policy_period_interval" json:"policy_period_interval"` PolicyMaxUpdatesPerPeriod int `db:"policy_max_updates_per_period" json:"policy_max_updates_per_period"` PolicyUpdateTimeout string `db:"policy_update_timeout" json:"policy_update_timeout"` VersionBreakdown []*VersionBreakdownEntry `db:"version_breakdown" json:"version_breakdown,omitempty"` Channel *Channel `db:"channel" json:"channel,omitempty"` InstancesStats InstancesStatusStats `db:"instances_stats" json:"instances_stats,omitempty"` }
Group represents a CoreRoller application's group.
type Instance ¶
type Instance struct { ID string `db:"id" json:"id"` IP string `db:"ip" json:"ip"` CreatedTs time.Time `db:"created_ts" json:"created_ts"` Application InstanceApplication `db:"application" json:"application,omitempty"` }
Instance represents an instance running one or more applications for which CoreRoller can provide updates.
type InstanceApplication ¶
type InstanceApplication struct { InstanceID string `db:"instance_id" json:"instance_id,omitempty"` ApplicationID string `db:"application_id" json:"application_id"` GroupID dat.NullString `db:"group_id" json:"group_id"` Version string `db:"version" json:"version"` CreatedTs time.Time `db:"created_ts" json:"created_ts"` Status dat.NullInt64 `db:"status" json:"status"` LastCheckForUpdates time.Time `db:"last_check_for_updates" json:"last_check_for_updates"` LastUpdateGrantedTs dat.NullTime `db:"last_update_granted_ts" json:"last_update_granted_ts"` LastUpdateVersion dat.NullString `db:"last_update_version" json:"last_update_version"` UpdateInProgress bool `db:"update_in_progress" json:"update_in_progress"` }
InstanceApplication represents some details about an application running on a given instance: current version of the app, last time the instance checked for updates for this app, etc.
type InstanceStatusHistoryEntry ¶
type InstanceStatusHistoryEntry struct { ID int `db:"id" json:"-"` Status int `db:"status" json:"status"` Version string `db:"version" json:"version"` CreatedTs time.Time `db:"created_ts" json:"created_ts"` InstanceID string `db:"instance_id" json:"-"` ApplicationID string `db:"application_id" json:"-"` GroupID string `db:"group_id" json:"-"` }
InstanceStatusHistoryEntry represents an entry in the instance status history.
type InstancesQueryParams ¶
type InstancesQueryParams struct { ApplicationID string `json:"application_id"` GroupID string `json:"group_id"` Status int `json:"status"` Version string `json:"version"` Page uint64 `json:"page"` PerPage uint64 `json:"perpage"` }
InstancesQueryParams represents a helper structure used to pass a set of parameters when querying instances.
type InstancesStatusStats ¶
type InstancesStatusStats struct { Total int `db:"total" json:"total"` Undefined int `db:"undefined" json:"undefined"` UpdateGranted int `db:"update_granted" json:"update_granted"` Error int `db:"error" json:"error"` Complete int `db:"complete" json:"complete"` Installed int `db:"installed" json:"installed"` Downloaded int `db:"downloaded" json:"downloaded"` Downloading int `db:"downloading" json:"downloading"` OnHold int `db:"onhold" json:"onhold"` }
InstancesStatusStats represents a set of statistics about the status of the instances that belong to a given group.
type Package ¶
type Package struct { ID string `db:"id" json:"id"` Type int `db:"type" json:"type"` Version string `db:"version" json:"version"` URL string `db:"url" json:"url"` Filename dat.NullString `db:"filename" json:"filename"` Description dat.NullString `db:"description" json:"description"` Size dat.NullString `db:"size" json:"size"` Hash dat.NullString `db:"hash" json:"hash"` CreatedTs time.Time `db:"created_ts" json:"created_ts"` ChannelsBlacklist []string `db:"channels_blacklist" json:"channels_blacklist"` ApplicationID string `db:"application_id" json:"application_id"` CoreosAction *CoreosAction `db:"coreos_action" json:"coreos_action"` }
Package represents a CoreRoller application's package.
type Team ¶
type Team struct { ID string `db:"id"` Name string `db:"name"` CreatedTs time.Time `db:"created_ts"` }
Team represents a CoreRoller team.
type UpdatesStats ¶
type UpdatesStats struct { TotalInstances int `db:"total_instances"` UpdatesToCurrentVersionGranted int `db:"updates_to_current_version_granted"` UpdatesToCurrentVersionAttempted int `db:"updates_to_current_version_attempted"` UpdatesToCurrentVersionSucceeded int `db:"updates_to_current_version_succeeded"` UpdatesToCurrentVersionFailed int `db:"updates_to_current_version_failed"` UpdatesGrantedInLastPeriod int `db:"updates_granted_in_last_period"` UpdatesInProgress int `db:"updates_in_progress"` UpdatesTimedOut int `db:"updates_timed_out"` }
UpdatesStats represents a set of statistics about the status of the updates that may be taking place in the instaces belonging to a given group.
type User ¶
type User struct { ID string `db:"id" json:"id"` Username string `db:"username" json:"username"` Secret string `db:"secret" json:"secret"` CreatedTs time.Time `db:"created_ts" json:"-"` TeamID string `db:"team_id" json:"team_id"` }
User represents a CoreRoller user.
type VersionBreakdownEntry ¶
type VersionBreakdownEntry struct { Version string `db:"version" json:"version"` Instances int `db:"instances" json:"instances"` Percentage float64 `db:"percentage" json:"percentage"` }
VersionBreakdownEntry represents the distribution of the versions currently installed in the instances belonging to a given group.