dsl struct tags; wip
diff --git a/openstack/compute/v2/extensions/secgroups/requests.go b/openstack/compute/v2/extensions/secgroups/requests.go
index a0bb025..48ff698 100644
--- a/openstack/compute/v2/extensions/secgroups/requests.go
+++ b/openstack/compute/v2/extensions/secgroups/requests.go
@@ -6,11 +6,9 @@
 )
 
 func commonList(client *gophercloud.ServiceClient, url string) pagination.Pager {
-	createPage := func(r pagination.PageResult) pagination.Page {
+	return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
 		return SecurityGroupPage{pagination.SinglePageBase(r)}
-	}
-
-	return pagination.NewPager(client, url, createPage)
+	})
 }
 
 // List will return a collection of all the security groups for a particular
@@ -29,11 +27,10 @@
 // security groups. It therefore represents the mutable attributes of a
 // security group.
 type GroupOpts struct {
-	// Required - the name of your security group.
-	Name string `json:"name"`
-
-	// Required - the description of your security group.
-	Description string `json:"description"`
+	// the name of your security group.
+	Name string `json:"name" required:"true"`
+	// the description of your security group.
+	Description string `json:"description" required:"true"`
 }
 
 // CreateOpts is the struct responsible for creating a security group.
@@ -46,42 +43,21 @@
 
 // ToSecGroupCreateMap builds the create options into a serializable format.
 func (opts CreateOpts) ToSecGroupCreateMap() (map[string]interface{}, error) {
-	sg := make(map[string]interface{})
-
-	if opts.Name == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToSecGroupCreateMap"
-		err.Argument = "secgroups.CreateOpts.Name"
-		return nil, err
-	}
-	if opts.Description == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToSecGroupCreateMap"
-		err.Argument = "secgroups.CreateOpts.Description"
-		return nil, err
-	}
-
-	sg["name"] = opts.Name
-	sg["description"] = opts.Description
-
-	return map[string]interface{}{"security_group": sg}, nil
+	return gophercloud.BuildRequestBody(opts, "security_group")
 }
 
 // Create will create a new security group.
 func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
-	var result CreateResult
-
-	reqBody, err := opts.ToSecGroupCreateMap()
+	var r CreateResult
+	b, err := opts.ToSecGroupCreateMap()
 	if err != nil {
-		result.Err = err
-		return result
+		r.Err = err
+		return r
 	}
-
-	_, result.Err = client.Post(rootURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Post(rootURL(client), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-
-	return result
+	return r
 }
 
 // UpdateOpts is the struct responsible for updating an existing security group.
@@ -94,79 +70,53 @@
 
 // ToSecGroupUpdateMap builds the update options into a serializable format.
 func (opts UpdateOpts) ToSecGroupUpdateMap() (map[string]interface{}, error) {
-	sg := make(map[string]interface{})
-
-	if opts.Name == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToSecGroupUpdateMap"
-		err.Argument = "secgroups.UpdateOpts.Name"
-		return nil, err
-	}
-	if opts.Description == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToSecGroupUpdateMap"
-		err.Argument = "secgroups.UpdateOpts.Description"
-		return nil, err
-	}
-
-	sg["name"] = opts.Name
-	sg["description"] = opts.Description
-
-	return map[string]interface{}{"security_group": sg}, nil
+	return gophercloud.BuildRequestBody(opts, "security_group")
 }
 
 // Update will modify the mutable properties of a security group, notably its
 // name and description.
 func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
-	var result UpdateResult
-
-	reqBody, err := opts.ToSecGroupUpdateMap()
+	var r UpdateResult
+	b, err := opts.ToSecGroupUpdateMap()
 	if err != nil {
-		result.Err = err
-		return result
+		r.Err = err
+		return r
 	}
-
-	_, result.Err = client.Put(resourceURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Put(resourceURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-
-	return result
+	return r
 }
 
 // Get will return details for a particular security group.
 func Get(client *gophercloud.ServiceClient, id string) GetResult {
-	var result GetResult
-	_, result.Err = client.Get(resourceURL(client, id), &result.Body, nil)
-	return result
+	var r GetResult
+	_, r.Err = client.Get(resourceURL(client, id), &r.Body, nil)
+	return r
 }
 
 // Delete will permanently delete a security group from the project.
 func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
-	var result gophercloud.ErrResult
-	_, result.Err = client.Delete(resourceURL(client, id), nil)
-	return result
+	var r gophercloud.ErrResult
+	_, r.Err = client.Delete(resourceURL(client, id), nil)
+	return r
 }
 
 // CreateRuleOpts represents the configuration for adding a new rule to an
 // existing security group.
 type CreateRuleOpts struct {
 	// Required - the ID of the group that this rule will be added to.
-	ParentGroupID string `json:"parent_group_id"`
-
+	ParentGroupID string `json:"parent_group_id" required:"true"`
 	// Required - the lower bound of the port range that will be opened.
-	FromPort int `json:"from_port"`
-
+	FromPort int `json:"from_port" required:"true"`
 	// Required - the upper bound of the port range that will be opened.
-	ToPort int `json:"to_port"`
-
+	ToPort int `json:"to_port" required:"true"`
 	// Required - the protocol type that will be allowed, e.g. TCP.
-	IPProtocol string `json:"ip_protocol"`
-
+	IPProtocol string `json:"ip_protocol" required:"true"`
 	// ONLY required if FromGroupID is blank. This represents the IP range that
 	// will be the source of network traffic to your security group. Use
 	// 0.0.0.0/0 to allow all IP addresses.
 	CIDR string `json:"cidr,omitempty"`
-
 	// ONLY required if CIDR is blank. This value represents the ID of a group
 	// that forwards traffic to the parent group. So, instead of accepting
 	// network traffic from an entire IP range, you can instead refine the
@@ -181,78 +131,30 @@
 
 // ToRuleCreateMap builds the create rule options into a serializable format.
 func (opts CreateRuleOpts) ToRuleCreateMap() (map[string]interface{}, error) {
-	if opts.ParentGroupID == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToRuleCreateMap"
-		err.Argument = "secgroups.CreateRuleOpts.ParentGroupID"
-		return nil, err
-	}
-	if opts.FromPort == 0 {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToRuleCreateMap"
-		err.Argument = "secgroups.CreateRuleOpts.FromPort"
-		return nil, err
-	}
-	if opts.ToPort == 0 {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToRuleCreateMap"
-		err.Argument = "secgroups.CreateRuleOpts.ToPort"
-		return nil, err
-	}
-	if opts.IPProtocol == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToRuleCreateMap"
-		err.Argument = "secgroups.CreateRuleOpts.IPProtocol"
-		return nil, err
-	}
-	if opts.CIDR == "" && opts.FromGroupID == "" {
-		err := gophercloud.ErrMissingInput{}
-		err.Function = "secgroups.ToRuleCreateMap"
-		err.Argument = "secgroups.CreateRuleOpts.CIDR/secgroups.CreateRuleOpts.FromGroupID"
-		return nil, err
-	}
-
-	rule := make(map[string]interface{})
-
-	rule["parent_group_id"] = opts.ParentGroupID
-	rule["from_port"] = opts.FromPort
-	rule["to_port"] = opts.ToPort
-	rule["ip_protocol"] = opts.IPProtocol
-
-	if opts.CIDR != "" {
-		rule["cidr"] = opts.CIDR
-	}
-	if opts.FromGroupID != "" {
-		rule["group_id"] = opts.FromGroupID
-	}
-
-	return map[string]interface{}{"security_group_rule": rule}, nil
+	return gophercloud.BuildRequestBody(opts, "security_group_rule")
 }
 
 // CreateRule will add a new rule to an existing security group (whose ID is
 // specified in CreateRuleOpts). You have the option of controlling inbound
 // traffic from either an IP range (CIDR) or from another security group.
 func CreateRule(client *gophercloud.ServiceClient, opts CreateRuleOptsBuilder) CreateRuleResult {
-	var result CreateRuleResult
-
-	reqBody, err := opts.ToRuleCreateMap()
+	var r CreateRuleResult
+	b, err := opts.ToRuleCreateMap()
 	if err != nil {
-		result.Err = err
-		return result
+		r.Err = err
+		return r
 	}
-
-	_, result.Err = client.Post(rootRuleURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
+	_, r.Err = client.Post(rootRuleURL(client), b, &r.Body, &gophercloud.RequestOpts{
 		OkCodes: []int{200},
 	})
-
-	return result
+	return r
 }
 
 // DeleteRule will permanently delete a rule from a security group.
 func DeleteRule(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
-	var result gophercloud.ErrResult
-	_, result.Err = client.Delete(resourceRuleURL(client, id), nil)
-	return result
+	var r gophercloud.ErrResult
+	_, r.Err = client.Delete(resourceRuleURL(client, id), nil)
+	return r
 }
 
 func actionMap(prefix, groupName string) map[string]map[string]string {
@@ -261,17 +163,17 @@
 	}
 }
 
-// AddServerToGroup will associate a server and a security group, enforcing the
+// AddServer will associate a server and a security group, enforcing the
 // rules of the group on the server.
-func AddServerToGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
-	var result gophercloud.ErrResult
-	_, result.Err = client.Post(serverActionURL(client, serverID), actionMap("add", groupName), &result.Body, nil)
-	return result
+func AddServer(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
+	var r gophercloud.ErrResult
+	_, r.Err = client.Post(serverActionURL(client, serverID), actionMap("add", groupName), &r.Body, nil)
+	return r
 }
 
-// RemoveServerFromGroup will disassociate a server from a security group.
-func RemoveServerFromGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
-	var result gophercloud.ErrResult
-	_, result.Err = client.Post(serverActionURL(client, serverID), actionMap("remove", groupName), &result.Body, nil)
-	return result
+// RemoveServer will disassociate a server from a security group.
+func RemoveServer(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
+	var r gophercloud.ErrResult
+	_, r.Err = client.Post(serverActionURL(client, serverID), actionMap("remove", groupName), &r.Body, nil)
+	return r
 }