|
@@ -0,0 +1,187 @@
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "strings"
|
|
|
+ "unicode"
|
|
|
+
|
|
|
+ "devel.mephi.ru/dyokunev/go-sdapi/sdApi1"
|
|
|
+ "github.com/alyu/configparser"
|
|
|
+ "github.com/gophercloud/gophercloud"
|
|
|
+ "github.com/gophercloud/gophercloud/openstack"
|
|
|
+ "github.com/gophercloud/gophercloud/openstack/identity/v3/projects"
|
|
|
+
|
|
|
+ models "devel.mephi.ru/dyokunev/go-asu-models"
|
|
|
+)
|
|
|
+
|
|
|
+// H E L P E R S
|
|
|
+
|
|
|
+func checkErr(err error) {
|
|
|
+ if err != nil {
|
|
|
+ panic(err)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func pointerFromBool(b bool) *bool {
|
|
|
+ return &b
|
|
|
+}
|
|
|
+
|
|
|
+func capitalize(str string) string {
|
|
|
+ runes := []rune(str)
|
|
|
+ runes[0] = unicode.ToUpper(runes[0])
|
|
|
+ return string(runes)
|
|
|
+}
|
|
|
+
|
|
|
+// O P E N S T A C K C L I E N T
|
|
|
+
|
|
|
+type OpenstackIdentityClient struct {
|
|
|
+ client *gophercloud.ServiceClient
|
|
|
+ config *configparser.Configuration
|
|
|
+}
|
|
|
+
|
|
|
+func initIdentityClient() *gophercloud.ServiceClient {
|
|
|
+ config, err := configparser.Read("./project_and_roles.conf")
|
|
|
+ checkErr(err)
|
|
|
+
|
|
|
+ section, err := config.Section("openstack")
|
|
|
+ checkErr(err)
|
|
|
+
|
|
|
+ opts := gophercloud.AuthOptions{
|
|
|
+ IdentityEndpoint: section.ValueOf("identity_endpoint"),
|
|
|
+ DomainName: section.ValueOf("domain_name"),
|
|
|
+ TenantName: section.ValueOf("project_name"),
|
|
|
+ Username: section.ValueOf("username"),
|
|
|
+ Password: section.ValueOf("password"),
|
|
|
+ }
|
|
|
+
|
|
|
+ provider, err := openstack.AuthenticatedClient(opts)
|
|
|
+ checkErr(err)
|
|
|
+
|
|
|
+ client, err := openstack.NewIdentityV3(provider, gophercloud.EndpointOpts{
|
|
|
+ Region: "Moscow",
|
|
|
+ })
|
|
|
+ checkErr(err)
|
|
|
+
|
|
|
+ return client
|
|
|
+}
|
|
|
+
|
|
|
+func projectsToMap(allProjects []projects.Project) map[int]projects.Project {
|
|
|
+ projectsMap := map[int]projects.Project{}
|
|
|
+
|
|
|
+ for _, project := range allProjects {
|
|
|
+ if project.Extra["PersNumber"] == nil {
|
|
|
+ panic(fmt.Sprintf("Project %s has no persNumber", project.Name))
|
|
|
+ }
|
|
|
+ persNumber := int(project.Extra["PersNumber"].(float64))
|
|
|
+ projectsMap[persNumber] = project
|
|
|
+ }
|
|
|
+
|
|
|
+ return projectsMap
|
|
|
+}
|
|
|
+
|
|
|
+func (osclient OpenstackIdentityClient) getProjectsMap(domainID string) map[int]projects.Project {
|
|
|
+ listOpts := projects.ListOpts{
|
|
|
+ DomainID: domainID,
|
|
|
+ Enabled: pointerFromBool(true),
|
|
|
+ IsDomain: pointerFromBool(false),
|
|
|
+ }
|
|
|
+
|
|
|
+ allPages, err := projects.List(osclient.client, listOpts).AllPages()
|
|
|
+ checkErr(err)
|
|
|
+
|
|
|
+ allProjects, err := projects.ExtractProjects(allPages)
|
|
|
+ checkErr(err)
|
|
|
+
|
|
|
+ return projectsToMap(allProjects)
|
|
|
+}
|
|
|
+
|
|
|
+func makeUpdateOpts(unit models.Unit, domainID string) projects.UpdateOpts {
|
|
|
+ updateOpts := projects.UpdateOpts{
|
|
|
+ DomainID: domainID,
|
|
|
+ Enabled: pointerFromBool(true),
|
|
|
+ IsDomain: pointerFromBool(false),
|
|
|
+ Name: fmt.Sprintf("%s [%v]", *unit.BriefName, *unit.PersNumber),
|
|
|
+ Description: *unit.Name,
|
|
|
+ Extra: map[string]interface{}{
|
|
|
+ "ParentPersNumber": unit.ParentId},
|
|
|
+ }
|
|
|
+
|
|
|
+ return updateOpts
|
|
|
+}
|
|
|
+
|
|
|
+func makeCreateOpts(unit models.Unit, domainID string) projects.CreateOpts {
|
|
|
+ createOpts := projects.CreateOpts{
|
|
|
+ DomainID: domainID,
|
|
|
+ Enabled: pointerFromBool(true),
|
|
|
+ IsDomain: pointerFromBool(false),
|
|
|
+ Name: fmt.Sprintf("%s [%v]", *unit.BriefName, *unit.PersNumber),
|
|
|
+ Description: *unit.Name,
|
|
|
+ Extra: map[string]interface{}{
|
|
|
+ "PersNumber": unit.PersNumber,
|
|
|
+ "ParentPersNumber": unit.ParentId},
|
|
|
+ }
|
|
|
+
|
|
|
+ return createOpts
|
|
|
+}
|
|
|
+
|
|
|
+// U N I T S
|
|
|
+
|
|
|
+func getAllUnits(config *configparser.Configuration) models.Units {
|
|
|
+ section, err := config.Section("sd.mephi.ru")
|
|
|
+ checkErr(err)
|
|
|
+
|
|
|
+ sdApi1.SetApiKey(section.ValueOf("api_key"))
|
|
|
+
|
|
|
+ allUnits, err := sdApi1.GetUnits()
|
|
|
+ checkErr(err)
|
|
|
+
|
|
|
+ return allUnits
|
|
|
+}
|
|
|
+
|
|
|
+func getCleanUnitsMap(config *configparser.Configuration) map[int]models.Unit {
|
|
|
+ allUnits := getAllUnits(config)
|
|
|
+ idToPersNum := map[int]int{}
|
|
|
+ cleanUnits := map[int]models.Unit{}
|
|
|
+
|
|
|
+ // Get all not nil units without duplicates
|
|
|
+ for _, unit := range allUnits {
|
|
|
+ if unit.PersNumber == nil || unit.IsHidden == 1 || unit.Name == nil || unit.BriefName == nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ idToPersNum[unit.Id] = *unit.PersNumber
|
|
|
+ existingUnit, ok := cleanUnits[*unit.PersNumber]
|
|
|
+ if !ok {
|
|
|
+ cleanUnits[*unit.PersNumber] = unit
|
|
|
+ } else {
|
|
|
+ cleanUnits[*unit.PersNumber] = newestUnit(existingUnit, unit)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for persNumber, unit := range cleanUnits {
|
|
|
+ // Change parent ID to parent persNumber
|
|
|
+ if unit.ParentId != nil {
|
|
|
+ parentPersNumber := idToPersNum[*unit.ParentId]
|
|
|
+ unit.ParentId = &parentPersNumber
|
|
|
+ }
|
|
|
+ // Clean names
|
|
|
+ *unit.Name = strings.Join(strings.Fields(*unit.Name), " ")
|
|
|
+ *unit.Name = capitalize(*unit.Name)
|
|
|
+ *unit.BriefName = strings.Join(strings.Fields(*unit.BriefName), " ")
|
|
|
+ *unit.BriefName = strings.ToUpper(*unit.BriefName)
|
|
|
+ cleanUnits[persNumber] = unit
|
|
|
+ }
|
|
|
+
|
|
|
+ return cleanUnits
|
|
|
+}
|
|
|
+
|
|
|
+func newestUnit(unit1 models.Unit, unit2 models.Unit) models.Unit {
|
|
|
+ if unit1.CreateOrderDate != nil && unit2.CreateOrderDate != nil {
|
|
|
+ if unit1.CreateOrderDate.Unix() > unit2.CreateOrderDate.Unix() {
|
|
|
+ return unit1
|
|
|
+ }
|
|
|
+ return unit2
|
|
|
+ }
|
|
|
+ return unit1
|
|
|
+
|
|
|
+}
|