github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/databaseserver.go (about) 1 /* 2 Copyright 2020-2021 Gravitational, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package types 18 19 import ( 20 "fmt" 21 "sort" 22 "time" 23 24 "github.com/gravitational/trace" 25 "golang.org/x/exp/maps" 26 27 "github.com/gravitational/teleport/api" 28 "github.com/gravitational/teleport/api/utils" 29 ) 30 31 // DatabaseServer represents a database access server. 32 type DatabaseServer interface { 33 // ResourceWithLabels provides common resource methods. 34 ResourceWithLabels 35 // GetNamespace returns server namespace. 36 GetNamespace() string 37 // GetTeleportVersion returns the teleport version the server is running on. 38 GetTeleportVersion() string 39 // GetHostname returns the server hostname. 40 GetHostname() string 41 // GetHostID returns ID of the host the server is running on. 42 GetHostID() string 43 // GetRotation gets the state of certificate authority rotation. 44 GetRotation() Rotation 45 // SetRotation sets the state of certificate authority rotation. 46 SetRotation(Rotation) 47 // String returns string representation of the server. 48 String() string 49 // Copy returns a copy of this database server object. 50 Copy() DatabaseServer 51 52 // CloneResource returns a copy of the DatabaseServer as a ResourceWithLabels 53 CloneResource() ResourceWithLabels 54 // GetDatabase returns the database this database server proxies. 55 GetDatabase() Database 56 // SetDatabase sets the database this database server proxies. 57 SetDatabase(Database) error 58 // ProxiedService provides common methods for a proxied service. 59 ProxiedService 60 } 61 62 // NewDatabaseServerV3 creates a new database server instance. 63 func NewDatabaseServerV3(meta Metadata, spec DatabaseServerSpecV3) (*DatabaseServerV3, error) { 64 s := &DatabaseServerV3{ 65 Metadata: meta, 66 Spec: spec, 67 } 68 if err := s.CheckAndSetDefaults(); err != nil { 69 return nil, trace.Wrap(err) 70 } 71 return s, nil 72 } 73 74 // GetVersion returns the database server resource version. 75 func (s *DatabaseServerV3) GetVersion() string { 76 return s.Version 77 } 78 79 // GetTeleportVersion returns the Teleport version the server is running. 80 func (s *DatabaseServerV3) GetTeleportVersion() string { 81 return s.Spec.Version 82 } 83 84 // GetHostname returns the database server hostname. 85 func (s *DatabaseServerV3) GetHostname() string { 86 return s.Spec.Hostname 87 } 88 89 // GetHostID returns ID of the host the server is running on. 90 func (s *DatabaseServerV3) GetHostID() string { 91 return s.Spec.HostID 92 } 93 94 // GetKind returns the resource kind. 95 func (s *DatabaseServerV3) GetKind() string { 96 return s.Kind 97 } 98 99 // GetSubKind returns the resource subkind. 100 func (s *DatabaseServerV3) GetSubKind() string { 101 return s.SubKind 102 } 103 104 // SetSubKind sets the resource subkind. 105 func (s *DatabaseServerV3) SetSubKind(sk string) { 106 s.SubKind = sk 107 } 108 109 // GetResourceID returns the resource ID. 110 func (s *DatabaseServerV3) GetResourceID() int64 { 111 return s.Metadata.ID 112 } 113 114 // SetResourceID sets the resource ID. 115 func (s *DatabaseServerV3) SetResourceID(id int64) { 116 s.Metadata.ID = id 117 } 118 119 // GetRevision returns the revision 120 func (s *DatabaseServerV3) GetRevision() string { 121 return s.Metadata.GetRevision() 122 } 123 124 // SetRevision sets the revision 125 func (s *DatabaseServerV3) SetRevision(rev string) { 126 s.Metadata.SetRevision(rev) 127 } 128 129 // GetMetadata returns the resource metadata. 130 func (s *DatabaseServerV3) GetMetadata() Metadata { 131 return s.Metadata 132 } 133 134 // GetNamespace returns the resource namespace. 135 func (s *DatabaseServerV3) GetNamespace() string { 136 return s.Metadata.Namespace 137 } 138 139 // SetExpiry sets the resource expiry time. 140 func (s *DatabaseServerV3) SetExpiry(expiry time.Time) { 141 s.Metadata.SetExpiry(expiry) 142 } 143 144 // Expiry returns the resource expiry time. 145 func (s *DatabaseServerV3) Expiry() time.Time { 146 return s.Metadata.Expiry() 147 } 148 149 // GetName returns the resource name. 150 func (s *DatabaseServerV3) GetName() string { 151 return s.Metadata.Name 152 } 153 154 // SetName sets the resource name. 155 func (s *DatabaseServerV3) SetName(name string) { 156 s.Metadata.Name = name 157 } 158 159 // GetRotation returns the server CA rotation state. 160 func (s *DatabaseServerV3) GetRotation() Rotation { 161 return s.Spec.Rotation 162 } 163 164 // SetRotation sets the server CA rotation state. 165 func (s *DatabaseServerV3) SetRotation(r Rotation) { 166 s.Spec.Rotation = r 167 } 168 169 // GetDatabase returns the database this database server proxies. 170 func (s *DatabaseServerV3) GetDatabase() Database { 171 if s.Spec.Database == nil { 172 return nil 173 } 174 return s.Spec.Database 175 } 176 177 // SetDatabase sets the database this database server proxies. 178 func (s *DatabaseServerV3) SetDatabase(database Database) error { 179 databaseV3, ok := database.(*DatabaseV3) 180 if !ok { 181 return trace.BadParameter("expected *DatabaseV3, got %T", database) 182 } 183 s.Spec.Database = databaseV3 184 return nil 185 } 186 187 // GetProxyID returns a list of proxy ids this server is connected to. 188 func (s *DatabaseServerV3) GetProxyIDs() []string { 189 return s.Spec.ProxyIDs 190 } 191 192 // SetProxyID sets the proxy ids this server is connected to. 193 func (s *DatabaseServerV3) SetProxyIDs(proxyIDs []string) { 194 s.Spec.ProxyIDs = proxyIDs 195 } 196 197 // String returns the server string representation. 198 func (s *DatabaseServerV3) String() string { 199 return fmt.Sprintf("DatabaseServer(Name=%v, Version=%v, Hostname=%v, HostID=%v, Database=%v)", 200 s.GetName(), s.GetTeleportVersion(), s.GetHostname(), s.GetHostID(), s.GetDatabase()) 201 } 202 203 // setStaticFields sets static resource header and metadata fields. 204 func (s *DatabaseServerV3) setStaticFields() { 205 s.Kind = KindDatabaseServer 206 s.Version = V3 207 } 208 209 // CheckAndSetDefaults checks and sets default values for any missing fields. 210 func (s *DatabaseServerV3) CheckAndSetDefaults() error { 211 s.setStaticFields() 212 if err := s.Metadata.CheckAndSetDefaults(); err != nil { 213 return trace.Wrap(err) 214 } 215 if s.Spec.HostID == "" { 216 return trace.BadParameter("missing database server HostID") 217 } 218 if s.Spec.Hostname == "" { 219 return trace.BadParameter("missing database server Hostname") 220 } 221 if s.Spec.Version == "" { 222 s.Spec.Version = api.Version 223 } 224 225 if s.Spec.Database == nil { 226 return trace.BadParameter("missing database server Database") 227 } 228 229 if err := s.Spec.Database.CheckAndSetDefaults(); err != nil { 230 return trace.Wrap(err) 231 } 232 233 return nil 234 } 235 236 // Origin returns the origin value of the resource. 237 func (s *DatabaseServerV3) Origin() string { 238 return s.Metadata.Origin() 239 } 240 241 // SetOrigin sets the origin value of the resource. 242 func (s *DatabaseServerV3) SetOrigin(origin string) { 243 s.Metadata.SetOrigin(origin) 244 } 245 246 // GetLabel retrieves the label with the provided key. If not found 247 // value will be empty and ok will be false. 248 func (s *DatabaseServerV3) GetLabel(key string) (value string, ok bool) { 249 if s.Spec.Database != nil { 250 if v, ok := s.Spec.Database.GetLabel(key); ok { 251 return v, ok 252 } 253 } 254 255 v, ok := s.Metadata.Labels[key] 256 return v, ok 257 } 258 259 // GetAllLabels returns all resource's labels. Considering: 260 // * Static labels from `Metadata.Labels` and `Spec.Database`. 261 // * Dynamic labels from `Spec.DynamicLabels`. 262 func (s *DatabaseServerV3) GetAllLabels() map[string]string { 263 staticLabels := map[string]string{} 264 maps.Copy(staticLabels, s.Metadata.Labels) 265 if s.Spec.Database != nil { 266 maps.Copy(staticLabels, s.Spec.Database.GetAllLabels()) 267 } 268 269 return staticLabels 270 } 271 272 // GetStaticLabels returns the database server static labels. 273 func (s *DatabaseServerV3) GetStaticLabels() map[string]string { 274 return s.Metadata.Labels 275 } 276 277 // SetStaticLabels sets the database server static labels. 278 func (s *DatabaseServerV3) SetStaticLabels(sl map[string]string) { 279 s.Metadata.Labels = sl 280 } 281 282 // Copy returns a copy of this database server object. 283 func (s *DatabaseServerV3) Copy() DatabaseServer { 284 return utils.CloneProtoMsg(s) 285 } 286 287 // CloneResource returns a copy of this database server object. 288 func (s *DatabaseServerV3) CloneResource() ResourceWithLabels { 289 return s.Copy() 290 } 291 292 // MatchSearch goes through select field values and tries to 293 // match against the list of search values. 294 func (s *DatabaseServerV3) MatchSearch(values []string) bool { 295 return MatchSearch(nil, values, nil) 296 } 297 298 // DatabaseServers represents a list of database servers. 299 type DatabaseServers []DatabaseServer 300 301 // Len returns the slice length. 302 func (s DatabaseServers) Len() int { return len(s) } 303 304 // Less compares database servers by name and host ID. 305 func (s DatabaseServers) Less(i, j int) bool { 306 switch { 307 case s[i].GetName() < s[j].GetName(): 308 return true 309 case s[i].GetName() > s[j].GetName(): 310 return false 311 default: 312 return s[i].GetHostID() < s[j].GetHostID() 313 } 314 } 315 316 // Swap swaps two database servers. 317 func (s DatabaseServers) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 318 319 // SortByCustom custom sorts by given sort criteria. 320 func (s DatabaseServers) SortByCustom(sortBy SortBy) error { 321 if sortBy.Field == "" { 322 return nil 323 } 324 325 // We assume sorting by type DatabaseServer, we are really 326 // wanting to sort its contained resource Database. 327 isDesc := sortBy.IsDesc 328 switch sortBy.Field { 329 case ResourceMetadataName: 330 sort.SliceStable(s, func(i, j int) bool { 331 return stringCompare(s[i].GetDatabase().GetName(), s[j].GetDatabase().GetName(), isDesc) 332 }) 333 case ResourceSpecDescription: 334 sort.SliceStable(s, func(i, j int) bool { 335 return stringCompare(s[i].GetDatabase().GetDescription(), s[j].GetDatabase().GetDescription(), isDesc) 336 }) 337 case ResourceSpecType: 338 sort.SliceStable(s, func(i, j int) bool { 339 return stringCompare(s[i].GetDatabase().GetType(), s[j].GetDatabase().GetType(), isDesc) 340 }) 341 default: 342 return trace.NotImplemented("sorting by field %q for resource %q is not supported", sortBy.Field, KindDatabaseServer) 343 } 344 345 return nil 346 } 347 348 // AsResources returns db servers as type resources with labels. 349 func (s DatabaseServers) AsResources() []ResourceWithLabels { 350 resources := make([]ResourceWithLabels, 0, len(s)) 351 for _, server := range s { 352 resources = append(resources, ResourceWithLabels(server)) 353 } 354 return resources 355 } 356 357 // GetFieldVals returns list of select field values. 358 func (s DatabaseServers) GetFieldVals(field string) ([]string, error) { 359 vals := make([]string, 0, len(s)) 360 switch field { 361 case ResourceMetadataName: 362 for _, server := range s { 363 vals = append(vals, server.GetDatabase().GetName()) 364 } 365 case ResourceSpecDescription: 366 for _, server := range s { 367 vals = append(vals, server.GetDatabase().GetDescription()) 368 } 369 case ResourceSpecType: 370 for _, server := range s { 371 vals = append(vals, server.GetDatabase().GetType()) 372 } 373 default: 374 return nil, trace.NotImplemented("getting field %q for resource %q is not supported", field, KindDatabaseServer) 375 } 376 377 return vals, nil 378 } 379 380 // ToDatabases converts database servers to a list of databases and 381 // deduplicates the databases by name. 382 func (s DatabaseServers) ToDatabases() []Database { 383 databases := make([]Database, 0, len(s)) 384 for _, server := range s { 385 databases = append(databases, server.GetDatabase()) 386 } 387 return DeduplicateDatabases(databases) 388 }