You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@trafficcontrol.apache.org by GitBox <gi...@apache.org> on 2019/10/29 16:43:59 UTC

[GitHub] [trafficcontrol] rawlinp commented on a change in pull request #4015: Rewrite /federations to Go - POST/PUT/DELETE

rawlinp commented on a change in pull request #4015: Rewrite /federations to Go - POST/PUT/DELETE
URL: https://github.com/apache/trafficcontrol/pull/4015#discussion_r340189103
 
 

 ##########
 File path: traffic_ops/traffic_ops_golang/federations/federations.go
 ##########
 @@ -167,3 +206,296 @@ ORDER BY
 	}
 	return feds, nil
 }
+
+// AddFederationResorverMappingsForCurrentUser is the handler for a POST request to /federations.
+// Confusingly, it does not create a federation, but is instead used to manipulate the resolvers
+// used by one or more particular Delivery Services for one or more particular Federations.
+func AddFederationResolverMappingsForCurrentUser(w http.ResponseWriter, r *http.Request) {
+	inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
+	tx := inf.Tx.Tx
+	if userErr != nil || sysErr != nil {
+		api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+		return
+	}
+	defer inf.Close()
+
+	mappings, userErr, sysErr := getMappingsFromRequestBody(*inf.Version, r.Body)
+	if userErr != nil || sysErr != nil {
+		api.HandleErr(w, r, tx, http.StatusBadRequest, userErr, sysErr)
+		return
+	}
+
+	if err := mappings.Validate(tx); err != nil {
+		errCode = http.StatusBadRequest
+		userErr = fmt.Errorf("validating request: %v", err)
+		api.HandleErr(w, r, tx, errCode, userErr, nil)
+		return
+	}
+
+	userErr, sysErr, errCode = addFederationResolverMappingsForCurrentUser(inf.User, tx, mappings)
+	if userErr != nil || sysErr != nil {
+		api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+		return
+	}
+
+	msg := fmt.Sprintf("%s successfully created federation resolvers.", inf.User.UserName)
+	if inf.Version.Minor <= 3 {
+		api.WriteResp(w, r, msg)
+	} else {
+		api.WriteRespAlertObj(w, r, tc.SuccessLevel, msg, msg)
+	}
+}
+
+// handles the main logic of the POST handler, separated out for convenience
+func addFederationResolverMappingsForCurrentUser(u *auth.CurrentUser, tx *sql.Tx, mappings []tc.DeliveryServiceFederationResolverMapping) (error, error, int) {
+	for _, fed := range mappings {
+		dsTenant, ok, err := dbhelpers.GetDSTenantIDFromXMLID(tx, fed.DeliveryService)
+		if err != nil {
+			return nil, err, http.StatusInternalServerError
+		} else if !ok {
+			return fmt.Errorf("'%s' - no such Delivery Service", fed.DeliveryService), nil, http.StatusConflict
+		}
+
+		if ok, err = tenant.IsResourceAuthorizedToUserTx(dsTenant, u, tx); err != nil {
+			err = fmt.Errorf("Checking user #%d tenancy permissions on DS '%s' (tenant #%d)", u.ID, fed.DeliveryService, dsTenant)
+			return nil, err, http.StatusInternalServerError
+		} else if !ok {
+			userErr := fmt.Errorf("'%s' - no such Delivery Service", fed.DeliveryService)
+			sysErr := fmt.Errorf("User '%s' requested unauthorized federation resolver mapping modification on the '%s' Delivery Service", u.UserName, fed.DeliveryService)
+			return userErr, sysErr, http.StatusConflict
+		}
+
+		fedID, ok, err := dbhelpers.GetFederationIDForUserIDByXMLID(tx, u.ID, fed.DeliveryService)
+		if err != nil {
+			return nil, fmt.Errorf("Getting Federation ID: %v", err), http.StatusInternalServerError
+		} else if !ok {
+			err = fmt.Errorf("No federation(s) found for user %s on delivery service '%s'.", u.UserName, fed.DeliveryService)
+			return err, nil, http.StatusConflict
+		}
+
+		inserted, err := addFederationResolverMappingsToFederation(fed.Mappings, fed.DeliveryService, fedID, tx)
+		if err != nil {
+			err = fmt.Errorf("Adding federation resolver mapping(s) to federation: %v", err)
+			return nil, err, http.StatusInternalServerError
+		}
+
+		changelogMsg := "FEDERATION DELIVERY SERVICE: %s, ID: %d, ACTION: User %s successfully added federation resolvers [ %s ]"
+		changelogMsg = fmt.Sprintf(changelogMsg, fed.DeliveryService, fedID, u.UserName, inserted)
+		api.CreateChangeLogRawTx(api.ApiChange, changelogMsg, u, tx)
+	}
+	return nil, nil, http.StatusOK
+}
+
+// adds federation resolver mappings for a particular delivery service to a given federation, creating said resolvers if
+// they don't already exist.
+func addFederationResolverMappingsToFederation(res tc.ResolverMapping, xmlid string, fed uint, tx *sql.Tx) (string, error) {
+	var resp string
+	if len(res.Resolve4) > 0 {
+		inserted, err := addFederationResolver(res.Resolve4, tc.FederationResolverType4, fed, tx)
+		if err != nil {
+			return "", err
+		}
+		resp = strings.Join(inserted, ", ")
+	}
+	if len(res.Resolve6) > 0 {
+		inserted, err := addFederationResolver(res.Resolve6, tc.FederationResolverType6, fed, tx)
+		if err != nil {
+			return "", err
+		}
+		resp += strings.Join(inserted, ", ")
+	}
+	return resp, nil
+}
+
+// adds federation resolvers of a specific type to the given federation
+func addFederationResolver(res []string, t tc.FederationResolverType, fedID uint, tx *sql.Tx) ([]string, error) {
+	inserted := []string{}
+	for _, r := range res {
+		var ip string
+		var id uint
+		if err := tx.QueryRow(insertResolverQuery, r, t).Scan(&ip, &id); err != nil && err != sql.ErrNoRows {
+			return nil, err
+		}
+		if ip != "" && id > 0 {
+			inserted = append(inserted, ip)
+			if _, err := tx.Exec(associateFederationWithResolverQuery, fedID, id); err != nil {
+				return nil, err
+			}
+		}
+
+	}
+
+	return inserted, nil
+}
+
+// RemoveFederationResolverMappingsForCurrentUser is the handler for a DELETE request to /federations
+// Confusingly, it does not delete a federation, but is instead used to remove an association
+// between all federation resolvers and all federations assigned to the authenticated user.
+func RemoveFederationResolverMappingsForCurrentUser(w http.ResponseWriter, r *http.Request) {
+	inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
+	tx := inf.Tx.Tx
+	if userErr != nil || sysErr != nil {
+		api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+		return
+	}
+	defer inf.Close()
+
+	ips, userErr, sysErr, errCode := removeFederationResolverMappingsForCurrentUser(tx, inf.User)
+	if userErr != nil || sysErr != nil {
+		api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+		return
+	}
+
+	// I'm not sure if I necessarily agree with treating this as a client error, but it's what Perl did.
+	if len(ips) < 1 {
+		errCode = http.StatusConflict
+		userErr = fmt.Errorf("No federation resolvers to delete for user %s", inf.User.UserName)
+		api.HandleErr(w, r, tx, errCode, userErr, nil)
+		return
+	}
+
+	ipList := fmt.Sprintf("[ %s ]", strings.Join(ips, ", "))
+	msg := fmt.Sprintf("%s successfully deleted all federation resolvers: %s", inf.User.UserName, ipList)
+	changelogMsg := fmt.Sprintf("USER: %s, ID: %d, ACTION: %s", inf.User.UserName, inf.User.ID, msg)
+	api.CreateChangeLogRawTx(api.ApiChange, changelogMsg, inf.User, tx)
+
+	if inf.Version.Minor <= 3 {
+		api.WriteResp(w, r, msg)
+	} else {
+		api.WriteRespAlertObj(w, r, tc.SuccessLevel, msg, msg)
+	}
+}
+
+// handles the main logic of the DELETE handler, separated out for convenience
+func removeFederationResolverMappingsForCurrentUser(tx *sql.Tx, u *auth.CurrentUser) ([]string, error, error, int) {
+	rows, err := tx.Query(deleteCurrentUserFederationResolversQuery, u.ID)
+	if err != nil {
+		if err == sql.ErrNoRows {
+			return nil, fmt.Errorf("No federation resolvers to delete for user %s", u.UserName), nil, http.StatusConflict
+		} else {
+			return nil, nil, fmt.Errorf("Deleting federation resolvers for user %s: %v", u.UserName, err), http.StatusInternalServerError
+		}
+	}
+	defer rows.Close()
+
+	ips := []string{}
+	for rows.Next() {
+		var ip string
+		if err := rows.Scan(&ip); err != nil {
+			return nil, nil, fmt.Errorf("Error scanning deleted resolver IP: %v", err), http.StatusInternalServerError
+		}
+		ips = append(ips, ip)
+	}
+	return ips, nil, nil, http.StatusOK
+}
+
+func ReplaceFederationResolverMappingsForCurrentUser(w http.ResponseWriter, r *http.Request) {
+	inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
+	tx := inf.Tx.Tx
+	if userErr != nil || sysErr != nil {
+		api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+		return
+	}
+	defer inf.Close()
+
+	ips, userErr, sysErr, errCode := removeFederationResolverMappingsForCurrentUser(tx, inf.User)
+	if userErr != nil || sysErr != nil {
+		api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+		return
+	}
+
+	ipList := fmt.Sprintf("[ %s ]", strings.Join(ips, ", "))
+	deletedMsg := fmt.Sprintf("%s successfully deleted all federation resolvers: %s", inf.User.UserName, ipList)
+	changelogMsg := fmt.Sprintf("USER: %s, ID: %d, ACTION: %s", inf.User.UserName, inf.User.ID, deletedMsg)
+	api.CreateChangeLogRawTx(api.ApiChange, changelogMsg, inf.User, tx)
+
+	mappings, userErr, sysErr := getMappingsFromRequestBody(*inf.Version, r.Body)
+	if userErr != nil || sysErr != nil {
+		api.HandleErr(w, r, tx, http.StatusBadRequest, userErr, sysErr)
+		return
+	}
+
+	if err := mappings.Validate(tx); err != nil {
+		errCode = http.StatusBadRequest
+		userErr = fmt.Errorf("validating request: %v", err)
+		api.HandleErr(w, r, tx, errCode, userErr, nil)
+		return
+	}
+
+	userErr, sysErr, errCode = addFederationResolverMappingsForCurrentUser(inf.User, tx, mappings)
+	if userErr != nil || sysErr != nil {
+		api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+		return
+	}
+
+	createdMsg := fmt.Sprintf("%s successfully created federation resolvers.", inf.User.UserName)
+	if inf.Version.Minor <= 3 {
 
 Review comment:
   ditto previous comment

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services