mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-10 22:41:41 +00:00
fix(terraform): read team per-model rpm/tpm limits from metadata and clear them on removal (#40439)
* fix(terraform): read team per-model rpm/tpm limits from metadata and clear them on removal Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * chore(terraform): drop explanatory comments from team per-model limit helper and tests Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: yassin <yassin@berri.ai> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
b64197c289
commit
4ddc5e2c29
2 changed files with 90 additions and 6 deletions
|
|
@ -263,11 +263,11 @@ func resourceLiteLLMTeamRead(d *schema.ResourceData, m interface{}) error {
|
|||
d.Set("team_member_tpm_limit", *teamResp.TeamMemberTPMLimit)
|
||||
}
|
||||
d.Set("team_member_key_duration", GetStringValue(teamResp.TeamMemberKeyDuration, d.Get("team_member_key_duration").(string)))
|
||||
if teamResp.ModelRPMLimit != nil {
|
||||
d.Set("model_rpm_limit", teamResp.ModelRPMLimit)
|
||||
if v := teamModelLimit(teamResp.ModelRPMLimit, teamResp.Metadata, "model_rpm_limit"); v != nil {
|
||||
d.Set("model_rpm_limit", v)
|
||||
}
|
||||
if teamResp.ModelTPMLimit != nil {
|
||||
d.Set("model_tpm_limit", teamResp.ModelTPMLimit)
|
||||
if v := teamModelLimit(teamResp.ModelTPMLimit, teamResp.Metadata, "model_tpm_limit"); v != nil {
|
||||
d.Set("model_tpm_limit", v)
|
||||
}
|
||||
if teamResp.AllowedPassthroughRoutes != nil {
|
||||
d.Set("allowed_passthrough_routes", teamResp.AllowedPassthroughRoutes)
|
||||
|
|
@ -364,14 +364,19 @@ func buildTeamData(d *schema.ResourceData, teamID string) map[string]interface{}
|
|||
"organization_id", "tpm_limit", "rpm_limit", "max_budget", "budget_duration", "models",
|
||||
"blocked", "team_member_permissions", "model_aliases", "guardrails", "prompts",
|
||||
"team_member_budget", "team_member_budget_duration", "team_member_rpm_limit",
|
||||
"team_member_tpm_limit", "team_member_key_duration", "model_rpm_limit",
|
||||
"model_tpm_limit", "allowed_passthrough_routes",
|
||||
"team_member_tpm_limit", "team_member_key_duration", "allowed_passthrough_routes",
|
||||
} {
|
||||
if v, ok := d.GetOk(key); ok {
|
||||
teamData[key] = v
|
||||
}
|
||||
}
|
||||
|
||||
for _, key := range []string{"model_rpm_limit", "model_tpm_limit"} {
|
||||
if v, ok := d.GetOk(key); ok || d.HasChange(key) {
|
||||
teamData[key] = v
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("soft_budget"); ok {
|
||||
teamData["soft_budget"] = v
|
||||
} else if d.HasChange("soft_budget") {
|
||||
|
|
@ -404,6 +409,14 @@ func buildTeamMetadata(d *schema.ResourceData) map[string]interface{} {
|
|||
return metadata
|
||||
}
|
||||
|
||||
func teamModelLimit(topLevel, metadata map[string]interface{}, key string) map[string]interface{} {
|
||||
if topLevel != nil {
|
||||
return topLevel
|
||||
}
|
||||
nested, _ := metadata[key].(map[string]interface{})
|
||||
return nested
|
||||
}
|
||||
|
||||
func splitTeamMetadata(raw map[string]interface{}) (map[string]string, []string, []string) {
|
||||
metadata := map[string]string{}
|
||||
var tags, alertEmails []string
|
||||
|
|
|
|||
|
|
@ -250,6 +250,77 @@ func TestTeamReadMapsNewFields(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTeamReadMapsPerModelLimitsFromMetadata(t *testing.T) {
|
||||
var captured map[string]interface{}
|
||||
srv := newTeamTestServer(t, &captured, `{
|
||||
"team_id": "team-1",
|
||||
"team_info": {
|
||||
"team_id": "team-1",
|
||||
"team_alias": "eng",
|
||||
"model_rpm_limit": null,
|
||||
"model_tpm_limit": null,
|
||||
"metadata": {
|
||||
"department": "eng",
|
||||
"model_rpm_limit": {"gpt-4o-mini": 250},
|
||||
"model_tpm_limit": {"gpt-4o-mini": 5000}
|
||||
}
|
||||
}
|
||||
}`)
|
||||
defer srv.Close()
|
||||
|
||||
d := newTeamResourceData(t, map[string]interface{}{
|
||||
"team_alias": "eng",
|
||||
"model_rpm_limit": map[string]interface{}{"gpt-4o-mini": 100},
|
||||
})
|
||||
d.SetId("team-1")
|
||||
|
||||
if err := resourceLiteLLMTeamRead(d, NewClient(srv.URL, "test-key", true)); err != nil {
|
||||
t.Fatalf("read returned error: %v", err)
|
||||
}
|
||||
if got := d.Get("model_rpm_limit"); !reflect.DeepEqual(got, map[string]interface{}{"gpt-4o-mini": 250}) {
|
||||
t.Errorf("model_rpm_limit = %v, want server value 250", got)
|
||||
}
|
||||
if got := d.Get("model_tpm_limit"); !reflect.DeepEqual(got, map[string]interface{}{"gpt-4o-mini": 5000}) {
|
||||
t.Errorf("model_tpm_limit = %v, want server value 5000", got)
|
||||
}
|
||||
if got := d.Get("metadata"); !reflect.DeepEqual(got, map[string]interface{}{"department": "eng"}) {
|
||||
t.Errorf("metadata = %v, want per-model limits kept out of the string map", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTeamUpdateClearsRemovedPerModelLimits(t *testing.T) {
|
||||
var captured map[string]interface{}
|
||||
srv := newTeamTestServer(t, &captured, `{"team_id":"team-1","team_info":{"team_id":"team-1","team_alias":"eng"}}`)
|
||||
defer srv.Close()
|
||||
|
||||
res := ResourceLiteLLMTeam()
|
||||
priorData := schema.TestResourceDataRaw(t, res.Schema, map[string]interface{}{
|
||||
"team_alias": "eng",
|
||||
"model_rpm_limit": map[string]interface{}{"gpt-4o-mini": 100},
|
||||
"model_tpm_limit": map[string]interface{}{"gpt-4o-mini": 5000},
|
||||
})
|
||||
priorData.SetId("team-1")
|
||||
prior := priorData.State()
|
||||
config := terraform.NewResourceConfigRaw(map[string]interface{}{"team_alias": "eng"})
|
||||
diff, err := res.Diff(context.Background(), prior, config, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("diff failed: %v", err)
|
||||
}
|
||||
d, err := schema.InternalMap(res.Schema).Data(prior, diff)
|
||||
if err != nil {
|
||||
t.Fatalf("data failed: %v", err)
|
||||
}
|
||||
|
||||
if err := resourceLiteLLMTeamUpdate(d, NewClient(srv.URL, "test-key", true)); err != nil {
|
||||
t.Fatalf("update failed: %v", err)
|
||||
}
|
||||
for _, k := range []string{"model_rpm_limit", "model_tpm_limit"} {
|
||||
if got, ok := captured[k]; !ok || !reflect.DeepEqual(got, map[string]interface{}{}) {
|
||||
t.Errorf("payload %s = %v (present=%v), want explicit empty map", k, got, ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rpm_limit_type / tpm_limit_type are accepted by /team/new but not
|
||||
// /team/update, so create must send them and update must not.
|
||||
func TestTeamLimitTypesSentOnCreateOnly(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue