Skip to content

Commit

Permalink
Add datasource for Firebase Android App Config (#7606) (#5425)
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <[email protected]>
  • Loading branch information
modular-magician authored Apr 4, 2023
1 parent 0f0a8c4 commit 58107e5
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/7606.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-datasource
firebase_android_app_config
```
147 changes: 147 additions & 0 deletions google-beta/data_source_google_firebase_android_app_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package google

import (
"context"
"fmt"

"google.golang.org/api/firebase/v1beta1"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
)

// Ensure the implementation satisfies the expected interfaces
var (
_ datasource.DataSource = &GoogleFirebaseAndroidAppConfigDataSource{}
_ datasource.DataSourceWithConfigure = &GoogleFirebaseAndroidAppConfigDataSource{}
)

func NewGoogleFirebaseAndroidAppConfigDataSource() datasource.DataSource {
return &GoogleFirebaseAndroidAppConfigDataSource{}
}

// GoogleFirebaseAndroidAppConfigDataSource defines the data source implementation
type GoogleFirebaseAndroidAppConfigDataSource struct {
client *firebase.Service
project types.String
}

type GoogleFirebaseAndroidAppConfigModel struct {
Id types.String `tfsdk:"id"`
AppId types.String `tfsdk:"app_id"`
ConfigFilename types.String `tfsdk:"config_filename"`
ConfigFileContents types.String `tfsdk:"config_file_contents"`
Project types.String `tfsdk:"project"`
}

func (d *GoogleFirebaseAndroidAppConfigDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_firebase_android_app_config"
}

func (d *GoogleFirebaseAndroidAppConfigDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
// This description is used by the documentation generator and the language server.
MarkdownDescription: "A Google Cloud Firebase Android application configuration",

Attributes: map[string]schema.Attribute{
"app_id": schema.StringAttribute{
Description: "The id of the Firebase Android App.",
MarkdownDescription: "The id of the Firebase Android App.",
Required: true,
},

"project": schema.StringAttribute{
Description: "The project id of the Firebase Android App.",
MarkdownDescription: "The project id of the Firebase Android App.",
Optional: true,
},

"config_filename": schema.StringAttribute{
Description: "The filename that the configuration artifact for the AndroidApp is typically saved as.",
MarkdownDescription: "The filename that the configuration artifact for the AndroidApp is typically saved as.",
Computed: true,
},

"config_file_contents": schema.StringAttribute{
Description: "The content of the XML configuration file as a base64-encoded string.",
MarkdownDescription: "The content of the XML configuration file as a base64-encoded string.",
Computed: true,
},

"id": schema.StringAttribute{
Description: "Firebase Android App Config identifier",
MarkdownDescription: "Firebase Android App Config identifier",
Computed: true,
},
},
}
}

func (d *GoogleFirebaseAndroidAppConfigDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}

p, ok := req.ProviderData.(*frameworkProvider)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *frameworkProvider, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)
return
}

d.client = p.NewFirebaseClient(p.userAgent, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
d.project = p.project
}

func (d *GoogleFirebaseAndroidAppConfigDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data GoogleFirebaseAndroidAppConfigModel
var metaData *ProviderMetaModel

// Read Provider meta into the meta model
resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &metaData)...)
if resp.Diagnostics.HasError() {
return
}

d.client.UserAgent = generateFrameworkUserAgentString(metaData, d.client.UserAgent)

client := firebase.NewProjectsAndroidAppsService(d.client)

// Read Terraform configuration data into the model
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

data.Project = getProjectFramework(data.Project, d.project, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}

appName := fmt.Sprintf("projects/%s/androidApps/%s/config", data.Project.ValueString(), data.AppId.ValueString())
data.Id = types.StringValue(appName)

clientResp, err := client.GetConfig(appName).Do()
if err != nil {
handleDatasourceNotFoundError(ctx, err, &resp.State, fmt.Sprintf("dataSourceFirebaseAndroidAppConfig %q", data.AppId.ValueString()), &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
}

tflog.Trace(ctx, "read firebase android app config data source")

data.ConfigFilename = types.StringValue(clientResp.ConfigFilename)
data.ConfigFileContents = types.StringValue(clientResp.ConfigFileContents)

// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
66 changes: 66 additions & 0 deletions google-beta/data_source_google_firebase_android_app_config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package google

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccDataSourceGoogleFirebaseAndroidAppConfig(t *testing.T) {
t.Parallel()

context := map[string]interface{}{
"project_id": GetTestProjectFromEnv(),
"package_name": "android.app." + RandString(t, 5),
"display_name": "tf-test Display Name AndroidAppConfig DataSource",
}

VcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProtoV5ProviderFactories: ProtoV5ProviderFactories(t),
Steps: []resource.TestStep{
{
Config: testAccDataSourceGoogleFirebaseAndroidAppConfig(context),
Check: resource.ComposeTestCheckFunc(
testAccDataSourceFirebaseAndroidAppConfigCheck("data.google_firebase_android_app_config.my_app_config"),
),
},
},
})
}

func testAccDataSourceGoogleFirebaseAndroidAppConfig(context map[string]interface{}) string {
return Nprintf(`
resource "google_firebase_android_app" "my_app_config" {
project = "%{project_id}"
package_name = "%{package_name}"
display_name = "%{display_name}"
}
data "google_firebase_android_app_config" "my_app_config" {
project = "%{project_id}"
app_id = google_firebase_android_app.my_app_config.app_id
}
`, context)
}

func testAccDataSourceFirebaseAndroidAppConfigCheck(datasourceName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
ds, ok := s.RootModule().Resources[datasourceName]
if !ok {
return fmt.Errorf("root module has no resource called %s", datasourceName)
}

if ds.Primary.Attributes["config_filename"] == "" {
return fmt.Errorf("config filename not found in data source")
}

if ds.Primary.Attributes["config_file_contents"] == "" {
return fmt.Errorf("config file contents not found in data source")
}

return nil
}
}
1 change: 1 addition & 0 deletions google-beta/framework_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,7 @@ func (p *frameworkProvider) DataSources(_ context.Context) []func() datasource.D
NewGoogleDnsManagedZoneDataSource,
NewGoogleDnsRecordSetDataSource,
NewGoogleDnsKeysDataSource,
NewGoogleFirebaseAndroidAppConfigDataSource,
NewGoogleFirebaseAppleAppConfigDataSource,
NewGoogleFirebaseWebAppConfigDataSource,
}
Expand Down

0 comments on commit 58107e5

Please sign in to comment.