Documentation
¶
Index ¶
- Constants
- Variables
- func GetRoleParts(arn string) (int64, string, error)
- func MakeRoleARN(account int64, name string) string
- func NewKeyringConfig(name, configDir string) *keyring.Config
- type AWSAccount
- type AWSRole
- type AWSRoleFlat
- type AWSSSO
- func (as *AWSSSO) Authenticate(printUrl bool, browser string) error
- func (as *AWSSSO) CreateToken() error
- func (as *AWSSSO) GetAccounts() ([]AccountInfo, error)
- func (as *AWSSSO) GetAllTags() *TagsList
- func (as *AWSSSO) GetDeviceAuthInfo() (DeviceAuthInfo, error)
- func (as *AWSSSO) GetRoleCredentials(accountId int64, role string) (RoleCredentials, error)
- func (as *AWSSSO) GetRoles(account AccountInfo) ([]RoleInfo, error)
- func (as *AWSSSO) RegisterClient() error
- func (as *AWSSSO) StartDeviceAuthorization() error
- func (as *AWSSSO) StoreKey() string
- type AccountInfo
- type Cache
- type CreateTokenResponse
- type DeviceAuthInfo
- type JsonStore
- func (jc *JsonStore) DeleteCreateTokenResponse(key string) error
- func (jc *JsonStore) DeleteRegisterClientData(key string) error
- func (jc *JsonStore) DeleteRoleCredentials(arn string) error
- func (jc *JsonStore) GetCreateTokenResponse(key string, token *CreateTokenResponse) error
- func (jc *JsonStore) GetRegisterClientData(key string, client *RegisterClientData) error
- func (jc *JsonStore) GetRoleCredentials(arn string, token *RoleCredentials) error
- func (jc *JsonStore) SaveCreateTokenResponse(key string, token CreateTokenResponse) error
- func (jc *JsonStore) SaveRegisterClientData(key string, client RegisterClientData) error
- func (jc *JsonStore) SaveRoleCredentials(arn string, token RoleCredentials) error
- type KeyringStore
- func (kr *KeyringStore) CreateTokenResponseKey(key string) string
- func (kr *KeyringStore) DeleteCreateTokenResponse(key string) error
- func (kr *KeyringStore) DeleteRegisterClientData(region string) error
- func (kr *KeyringStore) DeleteRoleCredentials(arn string) error
- func (kr *KeyringStore) GetCreateTokenResponse(key string, token *CreateTokenResponse) error
- func (kr *KeyringStore) GetRegisterClientData(region string, client *RegisterClientData) error
- func (kr *KeyringStore) GetRoleCredentials(arn string, token *RoleCredentials) error
- func (kr *KeyringStore) RegisterClientKey(ssoRegion string) string
- func (kr *KeyringStore) SaveCreateTokenResponse(key string, token CreateTokenResponse) error
- func (kr *KeyringStore) SaveRegisterClientData(region string, client RegisterClientData) error
- func (kr *KeyringStore) SaveRoleCredentials(arn string, token RoleCredentials) error
- type RegisterClientData
- type RoleCredentials
- type RoleInfo
- type RoleTags
- func (r *RoleTags) GetMatchCount(tags map[string]string) int
- func (r *RoleTags) GetMatchingRoles(tags map[string]string) []string
- func (r *RoleTags) GetPossibleUniqueRoles(tags map[string]string, key string, values []string) []string
- func (r *RoleTags) GetRoleTags(role string) map[string]string
- func (r *RoleTags) UsefulTags(tags map[string]string) []string
- type Roles
- func (r *Roles) AccountIds() []int64
- func (r *Roles) GetAccountRoles(accountId int64) map[string]*AWSRoleFlat
- func (r *Roles) GetAllRoles() []*AWSRoleFlat
- func (r *Roles) GetAllTags() *TagsList
- func (r *Roles) GetAllTagsSelect() *TagsList
- func (r *Roles) GetRole(accountId int64, roleName string) (*AWSRoleFlat, error)
- func (r *Roles) GetRoleChain(accountId int64, roleName string) []*AWSRoleFlat
- func (r *Roles) GetRoleTags() *RoleTags
- func (r *Roles) GetRoleTagsSelect() *RoleTags
- func (r *Roles) MatchingRoles(tags map[string]string) []*AWSRoleFlat
- type SSOAccount
- type SSOConfig
- type SSORole
- type SecureStorage
- type Settings
- type SettingsDefaults
- type StartDeviceAuthData
- type TagsList
Constants ¶
const ( // The default values for ODIC defined in: // https://tools.ietf.org/html/draft-ietf-oauth-device-flow-15#section-3.5 SLOW_DOWN_SEC = 5 RETRY_INTERVAL = 5 )
const ( KEYRING_NAME = "AWSSSOCli" KEYRING_ID = "aws-sso-cli" REGISTER_CLIENT_DATA_PREFIX = "client-data" CREATE_TOKEN_RESPONSE_PREFIX = "token-response" ENV_SSO_FILE_PASSWORD = "AWS_SSO_FILE_PASSPHRASE" )
const ( AWS_SESSION_EXPIRATION_FORMAT = "2006-01-02 15:04:05 -0700 MST" CACHE_TTL = 60 * 60 * 24 // 1 day in seconds )
Variables ¶
var DEFAULT_ACCOUNT_PRIMARY_TAGS []string = []string{
"AccountName",
"AccountAlias",
"Email",
}
var NewPassword string = ""
Functions ¶
func GetRoleParts ¶ added in v1.2.0
GetRoleParts returns the accountId & rolename for an ARN
func MakeRoleARN ¶ added in v1.2.0
Creates an AWS ARN for a role
func NewKeyringConfig ¶ added in v1.2.0
Types ¶
type AWSAccount ¶
type AWSAccount struct {
Alias string `json:"Alias,omitempty"` // from AWS
Name string `json:"Name,omitempty"` // from config
EmailAddress string `json:"EmailAddress,omitempty"`
Tags map[string]string `json:"Tags,omitempty"`
Roles map[string]*AWSRole `json:"Roles,omitempty"`
DefaultRegion string `json:"DefaultRegion,omitempty"`
}
AWSAccount and AWSRole is how we store the data
type AWSRoleFlat ¶
type AWSRoleFlat struct {
Id int `header:"Id"`
AccountId int64 `json:"AccountId" header:"AccountId"`
AccountName string `json:"AccountName" header:"AccountName"`
AccountAlias string `json:"AccountAlias" header:"AccountAlias"`
EmailAddress string `json:"EmailAddress" header:"EmailAddress"`
Expires string `json:"Expires" header:"Expires"`
Arn string `json:"Arn" header:"ARN"`
RoleName string `json:"RoleName" header:"Role"`
Profile string `json:"Profile" header:"Profile"`
DefaultRegion string `json:"DefaultRegion" header:"DefaultRegion"`
SSORegion string `json:"SSORegion" header:"SSORegion"`
StartUrl string `json:"StartUrl" header:"StartUrl"`
Tags map[string]string `json:"Tags"` // not supported by GenerateTable
Via string `json:"Via" header:"Via"`
SelectTags map[string]string // tags without spaces
}
This is what we always return for a role definition
func (*AWSRoleFlat) ExpiresIn ¶
func (r *AWSRoleFlat) ExpiresIn() (string, error)
ExpiresIn returns how long until this role expires as a string
func (*AWSRoleFlat) IsExpired ¶
func (r *AWSRoleFlat) IsExpired() bool
IsExpired returns if this role has expired or has no creds available
type AWSSSO ¶
type AWSSSO struct {
ClientName string `json:"ClientName"`
ClientType string `json:"ClientType"`
SsoRegion string `json:"ssoRegion"`
StartUrl string `json:"startUrl"`
ClientData RegisterClientData `json:"RegisterClient"`
DeviceAuth StartDeviceAuthData `json:"StartDeviceAuth"`
Token CreateTokenResponse `json:"TokenResponse"`
Accounts []AccountInfo `json:"Accounts"`
Roles map[string][]RoleInfo `json:"Roles"`
// contains filtered or unexported fields
}
func NewAWSSSO ¶
func NewAWSSSO(ssoRegion, startUrl string, store *SecureStorage) *AWSSSO
func (*AWSSSO) GetAccounts ¶
func (as *AWSSSO) GetAccounts() ([]AccountInfo, error)
func (*AWSSSO) GetAllTags ¶
returns all of the available tags from AWS SSO
func (*AWSSSO) GetDeviceAuthInfo ¶
func (as *AWSSSO) GetDeviceAuthInfo() (DeviceAuthInfo, error)
func (*AWSSSO) GetRoleCredentials ¶
func (as *AWSSSO) GetRoleCredentials(accountId int64, role string) (RoleCredentials, error)
func (*AWSSSO) RegisterClient ¶
Does the needful to talk to AWS or read our cache to get the RegisterClientData
func (*AWSSSO) StartDeviceAuthorization ¶
Makes the call to AWS to initiate the OIDC auth to the SSO provider.
type AccountInfo ¶
type AccountInfo struct {
Id int `yaml:"Id" json:"Id" header:"Id"`
AccountId string `yaml:"AccountId" json:"AccountId" header:"AccountId"`
AccountName string `yaml:"AccountName" json:"AccountName" header:"AccountName"`
EmailAddress string `yaml:"EmailAddress" json:"EmailAddress" header:"EmailAddress"`
}
func (AccountInfo) GetAccountId64 ¶
func (ai AccountInfo) GetAccountId64() int64
type Cache ¶
type Cache struct {
CreatedAt int64 `json:"CreatedAt"` // this cache.json
ConfigCreatedAt int64 `json:"ConfigCreatedAt"` // track config.yaml
History []string `json:"History,omitempty"`
Roles *Roles `json:"Roles,omitempty"`
// contains filtered or unexported fields
}
Our Cachefile. Sub-structs defined in sso/cache.go
func (*Cache) AddHistory ¶
adds a role to the History list up to the max number of entries
func (*Cache) Expired ¶
Expired returns if our Roles cache data is too old. If configFile is a valid file, we check the lastModificationTime of that file vs. the ConfigCreatedAt to determine if the cache needs to be updated
type CreateTokenResponse ¶ added in v1.2.0
type CreateTokenResponse struct {
AccessToken string `json:"accessToken"` // should be cached to issue new creds
ExpiresIn int64 `json:"expiresIn"` // number of seconds it expires in (from AWS)
ExpiresAt int64 `json:"expiresAt"` // Unix time when it expires
IdToken string `json:"IdToken"`
RefreshToken string `json:"RefreshToken"`
TokenType string `json:"tokenType"`
}
func (*CreateTokenResponse) Expired ¶ added in v1.2.0
func (t *CreateTokenResponse) Expired() bool
type DeviceAuthInfo ¶
type DeviceAuthInfo struct {
VerificationUri string
VerificationUriComplete string
UserCode string
}
func (*DeviceAuthInfo) OpenBrowser ¶ added in v1.2.0
func (da *DeviceAuthInfo) OpenBrowser() error
type JsonStore ¶ added in v1.2.0
type JsonStore struct {
RegisterClient map[string]RegisterClientData `json:"RegisterClient,omitempty"`
StartDeviceAuth map[string]StartDeviceAuthData `json:"StartDeviceAuth,omitempty"`
CreateTokenResponse map[string]CreateTokenResponse `json:"CreateTokenResponse,omitempty"`
RoleCredentials map[string]RoleCredentials `json:"RoleCredentials,omitempty"`
// contains filtered or unexported fields
}
Impliments SecureStorage insecurely
func OpenJsonStore ¶ added in v1.2.0
func (*JsonStore) DeleteCreateTokenResponse ¶ added in v1.2.0
DeleteCreateTokenResponse deletes the token from the json file
func (*JsonStore) DeleteRegisterClientData ¶ added in v1.2.0
func (*JsonStore) DeleteRoleCredentials ¶ added in v1.2.0
DeleteRoleCredentials deletes the token from the json file
func (*JsonStore) GetCreateTokenResponse ¶ added in v1.2.0
func (jc *JsonStore) GetCreateTokenResponse(key string, token *CreateTokenResponse) error
GetCreateTokenResponse retrieves the CreateTokenResponse from the json file
func (*JsonStore) GetRegisterClientData ¶ added in v1.2.0
func (jc *JsonStore) GetRegisterClientData(key string, client *RegisterClientData) error
func (*JsonStore) GetRoleCredentials ¶ added in v1.2.0
func (jc *JsonStore) GetRoleCredentials(arn string, token *RoleCredentials) error
GetRoleCredentials retrieves the RoleCredentials from the json file
func (*JsonStore) SaveCreateTokenResponse ¶ added in v1.2.0
func (jc *JsonStore) SaveCreateTokenResponse(key string, token CreateTokenResponse) error
SaveCreateTokenResponse stores the token in the json file
func (*JsonStore) SaveRegisterClientData ¶ added in v1.2.0
func (jc *JsonStore) SaveRegisterClientData(key string, client RegisterClientData) error
RegisterClientData
func (*JsonStore) SaveRoleCredentials ¶ added in v1.2.0
func (jc *JsonStore) SaveRoleCredentials(arn string, token RoleCredentials) error
SaveRoleCredentials stores the token in the json file
type KeyringStore ¶ added in v1.2.0
type KeyringStore struct {
// contains filtered or unexported fields
}
Impliments SecureStorage
func OpenKeyring ¶ added in v1.2.0
func OpenKeyring(cfg *keyring.Config) (*KeyringStore, error)
func (*KeyringStore) CreateTokenResponseKey ¶ added in v1.2.0
func (kr *KeyringStore) CreateTokenResponseKey(key string) string
func (*KeyringStore) DeleteCreateTokenResponse ¶ added in v1.2.0
func (kr *KeyringStore) DeleteCreateTokenResponse(key string) error
DeleteCreateTokenResponse deletes the CreateTokenResponse from the keyring
func (*KeyringStore) DeleteRegisterClientData ¶ added in v1.2.0
func (kr *KeyringStore) DeleteRegisterClientData(region string) error
Delete the RegisterClientData from the keychain
func (*KeyringStore) DeleteRoleCredentials ¶ added in v1.2.0
func (kr *KeyringStore) DeleteRoleCredentials(arn string) error
DeleteRoleCredentials deletes the RoleCredentials from the Keyring
func (*KeyringStore) GetCreateTokenResponse ¶ added in v1.2.0
func (kr *KeyringStore) GetCreateTokenResponse(key string, token *CreateTokenResponse) error
GetCreateTokenResponse retrieves the CreateTokenResponse from the keyring
func (*KeyringStore) GetRegisterClientData ¶ added in v1.2.0
func (kr *KeyringStore) GetRegisterClientData(region string, client *RegisterClientData) error
Get our RegisterClientData from the key chain
func (*KeyringStore) GetRoleCredentials ¶ added in v1.2.0
func (kr *KeyringStore) GetRoleCredentials(arn string, token *RoleCredentials) error
GetRoleCredentials retrieves the RoleCredentials from the Keyring
func (*KeyringStore) RegisterClientKey ¶ added in v1.2.0
func (kr *KeyringStore) RegisterClientKey(ssoRegion string) string
func (*KeyringStore) SaveCreateTokenResponse ¶ added in v1.2.0
func (kr *KeyringStore) SaveCreateTokenResponse(key string, token CreateTokenResponse) error
SaveCreateTokenResponse stores the token in the keyring
func (*KeyringStore) SaveRegisterClientData ¶ added in v1.2.0
func (kr *KeyringStore) SaveRegisterClientData(region string, client RegisterClientData) error
Save our RegisterClientData in the key chain
func (*KeyringStore) SaveRoleCredentials ¶ added in v1.2.0
func (kr *KeyringStore) SaveRoleCredentials(arn string, token RoleCredentials) error
SaveRoleCredentials stores the token in the arnring
type RegisterClientData ¶ added in v1.2.0
type RegisterClientData struct {
AuthorizationEndpoint string `json:"authorizationEndpoint,omitempty"`
ClientId string `json:"clientId"`
ClientIdIssuedAt int64 `json:"clientIdIssuedAt"`
ClientSecret string `json:"clientSecret"`
ClientSecretExpiresAt int64 `json:"clientSecretExpiresAt"`
TokenEndpoint string `json:"tokenEndpoint,omitempty"`
}
this struct should be cached for long term if possible
func (*RegisterClientData) Expired ¶ added in v1.2.0
func (r *RegisterClientData) Expired() bool
type RoleCredentials ¶ added in v1.2.0
type RoleCredentials struct {
RoleName string `json:"roleName"`
AccountId int64 `json:"accountId"`
AccessKeyId string `json:"accessKeyId"`
SecretAccessKey string `json:"secretAccessKey"`
SessionToken string `json:"sessionToken"`
Expiration int64 `json:"expiration"` // not in seconds!
}
func (*RoleCredentials) AccountIdStr ¶ added in v1.2.0
func (r *RoleCredentials) AccountIdStr() string
AccountIdStr returns our AccountId as a string
func (*RoleCredentials) ExpireString ¶ added in v1.2.0
func (r *RoleCredentials) ExpireString() string
func (*RoleCredentials) RoleArn ¶ added in v1.2.0
func (r *RoleCredentials) RoleArn() string
type RoleInfo ¶
type RoleInfo struct {
Id int `yaml:"Id" json:"Id" header:"Id"`
Arn string `yaml:"-" json:"-" header:"Arn"`
RoleName string `yaml:"RoleName" json:"RoleName" header:"RoleName"`
AccountId string `yaml:"AccountId" json:"AccountId" header:"AccountId"`
AccountName string `yaml:"AccountName" json:"AccountName" header:"AccountName"`
EmailAddress string `yaml:"EmailAddress" json:"EmailAddress" header:"EmailAddress"`
Expires int64 `yaml:"Expires" json:"Expires" header:"Expires"`
Profile string `yaml:"Profile" json:"Profile" header:"Profile"`
Region string `yaml:"Region" json:"Region" header:"Region"`
SSORegion string `header:"SSORegion"`
StartUrl string `header:"StartUrl"`
}
type RoleTags ¶
RoleTags provides an interface to find roles which match a set of tags
func (*RoleTags) GetMatchingRoles ¶
GetMatchingRoles returns the roles which match all the tags
func (*RoleTags) GetPossibleUniqueRoles ¶
func (r *RoleTags) GetPossibleUniqueRoles(tags map[string]string, key string, values []string) []string
GetPossibleMatches is like GetMatchingRoles, but takes another key and a list of values and it returns the unique set of all roles which match the base tags and all the possible combnations of key/values
type Roles ¶
type Roles struct {
// sso *AWSSSO
SSOName string `json:"SSOName"`
Accounts map[int64]*AWSAccount `json:"Accounts"`
SSORegion string `json:"SSORegion"`
StartUrl string `json:"StartUrl"`
DefaultRegion string `json:"DefaultRegion"`
}
main struct holding all our Roles discovered via AWS SSO and via the config.yaml
func (*Roles) AccountIds ¶
AccountIds returns all the configured AWS SSO AccountIds
func (*Roles) GetAccountRoles ¶
func (r *Roles) GetAccountRoles(accountId int64) map[string]*AWSRoleFlat
AccountRoles returns all the roles for a given account
func (*Roles) GetAllRoles ¶
func (r *Roles) GetAllRoles() []*AWSRoleFlat
AllRoles returns all the Roles as a flat list
func (*Roles) GetAllTags ¶
GetAllTags returns all the unique key/tag pairs for every role
func (*Roles) GetAllTagsSelect ¶ added in v1.2.0
returns all tags, but with with spaces replaced with underscores
func (*Roles) GetRole ¶
func (r *Roles) GetRole(accountId int64, roleName string) (*AWSRoleFlat, error)
Role returns the specified role as an AWSRoleFlat
func (*Roles) GetRoleChain ¶
func (r *Roles) GetRoleChain(accountId int64, roleName string) []*AWSRoleFlat
GetRoleChain figures out the AssumeRole chain required to assume the given role
func (*Roles) GetRoleTags ¶
GetRoleTags returns all the tags for each role
func (*Roles) GetRoleTagsSelect ¶ added in v1.2.0
GetRoleTagsSelect returns all the tags for each role with all the spaces replaced with underscores
func (*Roles) MatchingRoles ¶
func (r *Roles) MatchingRoles(tags map[string]string) []*AWSRoleFlat
MatchingRoles returns all the roles matching the given tags
type SSOAccount ¶
type SSOAccount struct {
Name string `koanf:"Name" yaml:"Name,omitempty"` // Admin configured Account Name
Tags map[string]string `koanf:"Tags" yaml:"Tags,omitempty" `
Roles map[string]*SSORole `koanf:"Roles" yaml:"Roles,omitempty"`
DefaultRegion string `koanf:"DefaultRegion" yaml:"DefaultRegion,omitempty"`
// contains filtered or unexported fields
}
func (*SSOAccount) GetAllTags ¶
func (a *SSOAccount) GetAllTags(id int64) map[string]string
GetAllTags returns all of the user defined tags and calculated tags for this account
func (*SSOAccount) HasRole ¶
func (a *SSOAccount) HasRole(arn string) bool
HasRole returns true/false if the given Account has the provided arn
type SSOConfig ¶
type SSOConfig struct {
SSORegion string `koanf:"SSORegion" yaml:"SSORegion"`
StartUrl string `koanf:"StartUrl" yaml:"StartUrl"`
Accounts map[int64]*SSOAccount `koanf:"Accounts" yaml:"Accounts,omitempty"`
DefaultRegion string `koanf:"DefaultRegion" yaml:"DefaultRegion,omitempty"`
// contains filtered or unexported fields
}
func (*SSOConfig) ConfigFile ¶ added in v1.2.0
ConfigFile returns the path to the config file
func (*SSOConfig) CreatedAt ¶
CreatedAt returns the Unix epoch seconds that this config file was created at
func (*SSOConfig) GetAllTags ¶
returns all of the available account & role tags for our SSO Provider
func (*SSOConfig) GetRoleMatches ¶
GetRoleMatches finds all the roles which match all of the given tags
type SSORole ¶
type SSORole struct {
ARN string `koanf:"ARN" yaml:"ARN"`
Profile string `koanf:"Profile" yaml:"Profile,omitempty"`
Tags map[string]string `koanf:"Tags" yaml:"Tags,omitempty"`
DefaultRegion string `koanf:"DefaultRegion" yaml:"DefaultRegion,omitempty"`
Via string `koanf:"Via" yaml:"Via,omitempty"`
// contains filtered or unexported fields
}
func (*SSORole) GetAccountId ¶
GetAccountId returns the accountId portion of the ARN or empty string on error
func (*SSORole) GetAccountId64 ¶
GetAccountId64 returns the accountId portion of the ARN
func (*SSORole) GetAllTags ¶
GetAllTags returns all of the user defined and calculated tags for this role
func (*SSORole) GetRoleName ¶
GetRoleName returns the role name portion of the ARN
func (*SSORole) SetParentAccount ¶
func (r *SSORole) SetParentAccount(a *SSOAccount)
type SecureStorage ¶ added in v1.2.0
type SecureStorage interface {
SaveRegisterClientData(string, RegisterClientData) error
GetRegisterClientData(string, *RegisterClientData) error
DeleteRegisterClientData(string) error
SaveCreateTokenResponse(string, CreateTokenResponse) error
GetCreateTokenResponse(string, *CreateTokenResponse) error
DeleteCreateTokenResponse(string) error
SaveRoleCredentials(string, RoleCredentials) error
GetRoleCredentials(string, *RoleCredentials) error
DeleteRoleCredentials(string) error
}
Define the interface for storing our AWS SSO data
type Settings ¶
type Settings struct {
Cache *Cache // our cache data
SSO map[string]*SSOConfig `koanf:"SSOConfig" yaml:"SSOConfig,omitempty"`
DefaultSSO string `koanf:"DefaultSSO" yaml:"DefaultSSO,omitempty"` // specify default SSO by key
SecureStore string `koanf:"SecureStore" yaml:"SecureStore,omitempty"` // json or keyring
JsonStore string `koanf:"JsonStore" yaml:"JsonStore,omitempty"`
PrintUrl bool `koanf:"PrintUrl" yaml:"PrintUrl,omitempty"`
Browser string `koanf:"Browser" yaml:"Browser,omitempty"`
ProfileFormat string `koanf:"ProfileFormat" yaml:"ProfileFormat,omitempty"`
AccountPrimaryTag []string `koanf:"AccountPrimaryTag" yaml:"AccountPrimaryTag"`
// contains filtered or unexported fields
}
func LoadSettings ¶
func LoadSettings(configFile, cacheFile string, defaults SettingsDefaults) (*Settings, error)
func (*Settings) ConfigFile ¶
func (*Settings) GetSelectedSSO ¶
GetSelectedSSO returns a valid SSOConfig based on user intput, configured value or our hardcoded 'Default' if it exists.
type SettingsDefaults ¶ added in v1.2.0
type StartDeviceAuthData ¶ added in v1.2.0
type TagsList ¶
TagsList provides the necessary struct finding all the possible tag key/values
func NewTagsList ¶
func NewTagsList() *TagsList
func (*TagsList) UniqueKeys ¶
Returns a sorted unique list of tag keys, removing any keys which have already been picked
func (*TagsList) UniqueValues ¶
Returns a sorted unique list of tag values for the given key