github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/group.go (about) 1 /* 2 * Copyright 2020 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. 3 */ 4 5 package govcd 6 7 import ( 8 "fmt" 9 "net/http" 10 "net/url" 11 12 "github.com/vmware/go-vcloud-director/v2/types/v56" 13 "github.com/vmware/go-vcloud-director/v2/util" 14 ) 15 16 // OrgGroup defines group structure 17 type OrgGroup struct { 18 Group *types.Group 19 client *Client 20 AdminOrg *AdminOrg // needed to be able to update, as the list of roles is found in the Org 21 } 22 23 // NewGroup creates a new group structure which still needs to have Group attribute populated 24 func NewGroup(cli *Client, org *AdminOrg) *OrgGroup { 25 return &OrgGroup{ 26 Group: new(types.Group), 27 client: cli, 28 AdminOrg: org, 29 } 30 } 31 32 // CreateGroup creates a group in Org. Supported provider types are `OrgUserProviderIntegrated` and 33 // `OrgUserProviderSAML`. 34 // 35 // Note. This request will return HTTP 403 if Org is not configured for SAML or LDAP usage. 36 func (adminOrg *AdminOrg) CreateGroup(group *types.Group) (*OrgGroup, error) { 37 if err := validateCreateUpdateGroup(group); err != nil { 38 return nil, err 39 } 40 41 groupCreateHREF, err := url.ParseRequestURI(adminOrg.AdminOrg.HREF) 42 if err != nil { 43 return nil, fmt.Errorf("error parsing admin org url: %s", err) 44 } 45 groupCreateHREF.Path += "/groups" 46 47 grpgroup := NewGroup(adminOrg.client, adminOrg) 48 // Add default XML types 49 group.Xmlns = types.XMLNamespaceVCloud 50 group.Type = types.MimeAdminGroup 51 52 _, err = adminOrg.client.ExecuteRequest(groupCreateHREF.String(), http.MethodPost, 53 types.MimeAdminGroup, "error creating group: %s", group, grpgroup.Group) 54 if err != nil { 55 return nil, err 56 } 57 58 return grpgroup, nil 59 } 60 61 // GetGroupByHref retrieves group by HREF 62 func (adminOrg *AdminOrg) GetGroupByHref(href string) (*OrgGroup, error) { 63 orgGroup := NewGroup(adminOrg.client, adminOrg) 64 65 _, err := adminOrg.client.ExecuteRequest(href, http.MethodGet, 66 types.MimeAdminUser, "error getting group: %s", nil, orgGroup.Group) 67 68 if err != nil { 69 return nil, err 70 } 71 return orgGroup, nil 72 } 73 74 // GetGroupByName retrieves group by Name 75 func (adminOrg *AdminOrg) GetGroupByName(name string, refresh bool) (*OrgGroup, error) { 76 if refresh { 77 err := adminOrg.Refresh() 78 if err != nil { 79 return nil, err 80 } 81 } 82 83 for _, group := range adminOrg.AdminOrg.Groups.Group { 84 if group.Name == name { 85 return adminOrg.GetGroupByHref(group.HREF) 86 } 87 } 88 return nil, ErrorEntityNotFound 89 } 90 91 // GetGroupById retrieves group by Id 92 func (adminOrg *AdminOrg) GetGroupById(id string, refresh bool) (*OrgGroup, error) { 93 if refresh { 94 err := adminOrg.Refresh() 95 if err != nil { 96 return nil, err 97 } 98 } 99 100 for _, group := range adminOrg.AdminOrg.Groups.Group { 101 if equalIds(id, group.ID, group.HREF) { 102 return adminOrg.GetGroupByHref(group.HREF) 103 } 104 } 105 return nil, ErrorEntityNotFound 106 } 107 108 // GetGroupByNameOrId retrieves group by Name or Id. Id is prioritized for search 109 func (adminOrg *AdminOrg) GetGroupByNameOrId(identifier string, refresh bool) (*OrgGroup, error) { 110 getByName := func(name string, refresh bool) (interface{}, error) { return adminOrg.GetGroupByName(name, refresh) } 111 getById := func(name string, refresh bool) (interface{}, error) { return adminOrg.GetGroupById(name, refresh) } 112 entity, err := getEntityByNameOrId(getByName, getById, identifier, refresh) 113 if entity == nil { 114 return nil, err 115 } 116 return entity.(*OrgGroup), err 117 } 118 119 // Update allows to update group. vCD API allows to update only role 120 func (group *OrgGroup) Update() error { 121 util.Logger.Printf("[TRACE] Updating group: %s", group.Group.Name) 122 123 if err := validateCreateUpdateGroup(group.Group); err != nil { 124 return err 125 } 126 127 groupHREF, err := url.ParseRequestURI(group.Group.Href) 128 if err != nil { 129 return fmt.Errorf("error getting HREF for group %s : %s", group.Group.Href, err) 130 } 131 util.Logger.Printf("[TRACE] Url for updating group : %s and name: %s", groupHREF.String(), group.Group.Name) 132 133 _, err = group.client.ExecuteRequest(groupHREF.String(), http.MethodPut, 134 types.MimeAdminGroup, "error updating group : %s", copyWithoutUserList(group.Group), nil) 135 return err 136 } 137 138 // Delete removes a group 139 func (group *OrgGroup) Delete() error { 140 if err := validateDeleteGroup(group.Group); err != nil { 141 return err 142 } 143 144 groupHREF, err := url.ParseRequestURI(group.Group.Href) 145 if err != nil { 146 return fmt.Errorf("error getting HREF for group %s : %s", group.Group.Name, err) 147 } 148 util.Logger.Printf("[TRACE] Url for deleting group : %s and name: %s", groupHREF, group.Group.Name) 149 150 return group.client.ExecuteRequestWithoutResponse(groupHREF.String(), http.MethodDelete, 151 types.MimeAdminGroup, "error deleting group : %s", nil) 152 } 153 154 // validateCreateGroup checks if mandatory fields are set for group creation and update 155 func validateCreateUpdateGroup(group *types.Group) error { 156 if group == nil { 157 return fmt.Errorf("group cannot be nil") 158 } 159 160 if group.Name == "" { 161 return fmt.Errorf("group must have a name") 162 } 163 164 if group.ProviderType == "" { 165 return fmt.Errorf("group must have provider type set") 166 } 167 168 if group.Role.HREF == "" { 169 return fmt.Errorf("group role must have HREF set") 170 } 171 return nil 172 } 173 174 // validateDeleteGroup checks if mandatory fields are set for delete 175 func validateDeleteGroup(group *types.Group) error { 176 if group == nil { 177 return fmt.Errorf("group cannot be nil") 178 } 179 180 if group.Href == "" { 181 return fmt.Errorf("HREF must be set to delete group") 182 } 183 184 return nil 185 } 186 187 // copyWithoutUserList returns a copy of the given group, with the UserList attribute set to nil. 188 // This can and should be used to interact with VCD after a group read from the LDAP, 189 // as having this list populated will return an error 400 as VCD doesn't expect this list to be updatable. 190 func copyWithoutUserList(group *types.Group) *types.Group { 191 return &types.Group{ 192 XMLName: group.XMLName, 193 Xmlns: group.Xmlns, 194 ID: group.ID, 195 Href: group.Href, 196 Type: group.Type, 197 Description: group.Description, 198 Name: group.Name, 199 ProviderType: group.ProviderType, 200 Role: group.Role, 201 UsersList: nil, 202 } 203 }