Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VIP Integrations: Improves reading of config files and add multiple configs support of same integration #5643

Open
wants to merge 24 commits into
base: develop
Choose a base branch
from

Conversation

mehmoodak
Copy link
Member

@mehmoodak mehmoodak commented Jun 13, 2024

Description

  • Refactored "Integrations Framework" to make reading of config files generic i.e. read config by integration type available inside data instead of slug available in file name.
  • Updated `Integrations Framework" to add the ability of configuring multiple instances of same integration.

Changelog Description

Improved VIP Integrations

  • Improves reading of config files to make the implementation more generic.
  • Adds the ability of configuring multiple instances of same integration.

Pre-review checklist

  • This change works and has been tested locally or in Codespaces.
  • This change works and has been tested on a sandbox.
  • This change has relevant unit tests (if applicable).
  • [N/A] This change uses a rollout method to ease with deployment (if applicable - especially for large scale actions that require writes).
  • This change has relevant documentation additions / updates (if applicable).
  • I've created a changelog description that aligns with the provided examples.

Pre-deploy checklist

  • Update ConfigMaps generating from backend
  • Reload ConfigMaps of all envs to make sure that config files have type attribute. We do have this reload ability available in backend API.
  • VIP staff: Ensure any alerts added/updated conform to internal standards (see internal documentation).

Steps to Test

  1. Checkout this PR

  2. Run the vip site locally using vip dev-env start --slug [YOUR_SLUG] (if no env is available then create it)

  3. Create integration config files inside php container and place configs (we have to do it manually because as of now vip dev-env doesn't have support to auto create this folder/file while creating new envs)

    • docker exec -it [CONTAINER_NAME] /bin/sh
    • mkdir /wp/config/integrations-config
    • touch /wp/config/integrations-config/parsely-config.php and adds following content
      • parsely can be replaced with any other slug of the integration
    return array(
      'type' => 'parsely',
      'env' => array(
      	'status' => 'enabled',
      	'config' => array (
      		'site_id' => 'site.com',
      		'api_secret' => 'site_api_secret',
      		'metadata_secret' => 'site_metadata_secret',
      	)
      ),
      'network_sites' => array (
      	'1' => array (
      		'status' => 'enabled',
      		'config' => array (
      			'site_id' => 'site1.com',
      			'api_secret' => 'site_api_secret_1',
      			'metadata_secret' => 'site_metadata_secret_1',
      		)
      	),
      	'2' => array (
      		'status' => 'enabled',
      		'config' => array (
      			'site_id' => 'site2.com',
      			'api_secret' => 'site_api_secret_2',
      			'metadata_secret' => 'site_metadata_secret_2',
      		)
      	),
      )
    );
    
  4. Create config files for multiple integrations.

    • touch /wp/config/integrations-config/[SLUG]-123-config.php and adds following content
    • Replace slug with anything
    <?php
    
    return array(
      'type' => 'slug',
      'label' => 'Slug 123',
      'env' => array(
      	'status' => 'enabled',
            'config' => array (
      		'key' => 'slug-123',
      	)
      )
    );
    
    • touch /wp/config/integrations-config/[SLUG]-456-config.php and adds following content
    <?php
    
    return array(
      'type' => 'slug',
      'label' => 'Slug 456',
      'env' => array(
      	'status' => 'enabled',
            'config' => array (
      		'key' => 'slug-456',
      	)
      )
    );
    
  5. Restart vip dev-env to apply changes in these config files.

  6. Verify integration enablement with different combinations of vip configs e.g. wp-parsely plugin is activated with the SiteID and secrets which are provided by VIP (credentails support will be available on v3.9 and above).

  7. Apart from enabling the plugin via VIP config, customer can also enables it by placing \Automattic\VIP\Integrations\activate( 'parsely' ); in plugin-loader.php file so better to also test this flow also.

@mehmoodak mehmoodak self-assigned this Jun 13, 2024
@mehmoodak mehmoodak changed the title Improves reading of config files in IntegrationVIPConfig class and add support for handling multiple configs Integrations: Improves reading of config files and add support for multiple configs Jun 13, 2024
@mehmoodak mehmoodak force-pushed the cafe-919/update-IntegrationVipConfig-class-to-read-files-in-generic-way branch from dcd3c2d to 13fdecc Compare June 14, 2024 18:28
Copy link

codecov bot commented Jun 14, 2024

Codecov Report

Attention: Patch coverage is 91.25000% with 7 lines in your changes missing coverage. Please review.

Project coverage is 29.60%. Comparing base (192958b) to head (fe14e06).
Report is 25 commits behind head on develop.

Files Patch % Lines
integrations/vip-integrations-config.php 82.35% 6 Missing ⚠️
vip-integrations.php 50.00% 1 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##             develop    #5643      +/-   ##
=============================================
+ Coverage      29.53%   29.60%   +0.06%     
- Complexity      4779     4792      +13     
=============================================
  Files            282      282              
  Lines          20597    20608      +11     
=============================================
+ Hits            6083     6100      +17     
+ Misses         14514    14508       -6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@mehmoodak mehmoodak force-pushed the cafe-919/update-IntegrationVipConfig-class-to-read-files-in-generic-way branch 3 times, most recently from 4377568 to c5586c6 Compare June 16, 2024 19:01
@mehmoodak mehmoodak force-pushed the cafe-919/update-IntegrationVipConfig-class-to-read-files-in-generic-way branch from c5586c6 to 4653616 Compare June 16, 2024 19:04
@mehmoodak mehmoodak changed the title Integrations: Improves reading of config files and add support for multiple configs VIP Integrations: Improves reading of config files and add support for multiple configs of same integration Jun 17, 2024
@mehmoodak mehmoodak changed the title VIP Integrations: Improves reading of config files and add support for multiple configs of same integration VIP Integrations: Improves reading of config files and add multiple configs support of same integration Jun 17, 2024
*
* @return array<Env_Integration_Status>
*/
private function get_site_statuses() {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method moved from IntegrationVipConfig file and added multi status support.

public function set_vip_config( IntegrationVipConfig $vip_config ): void {
if ( ! $this->is_active() ) {
trigger_error( sprintf( 'Configuration info can only assigned if integration is active.' ), E_USER_WARNING ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
public function get_site_configs() {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method moved from IntegrationVipConfig file and added multi configs support.

* @return void
*/
public function activate_platform_integrations() {
public function activate_platform_integrations( VipIntegrationsConfig $vip_integrations_config ) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For easier mocking providing config as a param.


return false;
}, E_USER_WARNING );
$this->original_error_reporting = setup_custom_error_reporting();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoided duplication across files and added following methods:

  • setup_custom_error_reporting
  • reset_custom_error_reporting

@@ -147,19 +141,435 @@ public function test__is_active_returns_false_when_integration_is_not_active():
$this->assertFalse( $integration->is_active() );
}

public function test__set_vip_config_function_throws_error_if_integration_is_not_active(): void {
public function test__is_active_via_vip_returns_false_if_empty_config_is_provided(): void {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Moved methods from test-integration-config.php class to here.
  • Updated methods to allow multiple configs.

@mehmoodak mehmoodak marked this pull request as ready for review June 17, 2024 10:15
@mehmoodak mehmoodak requested a review from a team as a code owner June 17, 2024 10:15
Copy link

sonarcloud bot commented Jun 20, 2024

@WPprodigy
Copy link
Contributor

Pausing on this for now. Will revisit when we're adding in this functionality.

@WPprodigy WPprodigy closed this Jul 1, 2024
@mehmoodak
Copy link
Member Author

Had some discussions with Cantina team and we decided to reopen this Pull Request while keeping the existing proposal as is.

@mehmoodak mehmoodak reopened this Aug 15, 2024
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Changed the name to vip-integrations-config.php and refactored the code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Changed the name from integration-vip-config.php
  • Refactored get_vip_config_from_file to read all files at once and rename the function to read_config_files
  • Moved is_active_via_vip, get_site_status, get_site_config and get_value_from_config to Integration class because it makes more sense there. Apart from this added support for multiple configs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • FakeMultiConfigIntegration class for multi config integration.

* @private
*/
public function is_active_via_vip(): bool {
return in_array( Env_Integration_Status::ENABLED, $this->get_site_statuses() );
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For multiple setups enable the integration if any of the source is ENABLED.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think we absolutely need the concept of a parent integration present here. The parent should be the one deciding if the whole thing should be enabled (and at what version) for the env/subsite.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In #5644 we are checking enablement on parent before getting any status from child (src). This PR is mainly just a refactoring PR that supports composable cases.

/**
* Setup custom error handler and returns current level of error reporting.
*/
function setup_custom_error_reporting(): int {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved duplicated code to following methods

  • setup_custom_error_reporting
  • reset_custom_error_reporting

@mehmoodak
Copy link
Member Author

Made some minor changes and now this PR is good for review.

@@ -7,7 +7,8 @@

namespace Automattic\VIP\Integrations;

use Automattic\VIP\Integrations\IntegrationVipConfig;
use Org_Integration_Status;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we're actually moving away from differing the statuses and want it all in one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes please, let's normalize and just have one "statuses" enum.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As of now we don't support all statuses on ORG and ENV so I think the distinction makes sense and explaining the code.

if ( ! $this->is_active() ) {
trigger_error( sprintf( 'Configuration info can only assigned if integration is active.' ), E_USER_WARNING ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
public function set_vip_configs( array $vip_configs ): void {
$this->vip_configs = $vip_configs;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come we're removing the active check?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are only using set_vip_configs in one place which is already handling the is_active case, therefore removed it.

}

// Return config object if integration have only one config else return all configs.
return ( ! $this->have_multiple_setups && isset( $configs[0] ) ) ? $configs[0] : $configs;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides Composable, how many other integrations will have multiple set-ups? Just wondering, but is this something that can be handled elsewhere? :/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some nice benefits to having individual sources be able to cascade down with their own configs like the other integrations. Helps prevent duplication for network sites for example, and keeps things logically operating the same way.

@@ -7,7 +7,8 @@

namespace Automattic\VIP\Integrations;

use Automattic\VIP\Integrations\IntegrationVipConfig;
use Org_Integration_Status;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes please, let's normalize and just have one "statuses" enum.

Comment on lines +185 to +187
if ( $this->get_value_from_config( $vip_config, 'org', 'status' ) === Org_Integration_Status::BLOCKED ) {
return [ Org_Integration_Status::BLOCKED ];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we instead make these decisions in goop before setting the configmap?

Anything that doesn't belong on a site config (based on inheritance from the client level) shouldn't end up in the configmap in the first place.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Currently we can get the info about why a particular integration doesn't have any data in ConfigMap by just looking at the file. If we move it to GOOP then we loses this visibility which effect debugging if user doesn't have enough permissions.

  2. In future we can have integrations that want to show some notification in WP Dashboard if the plugin is blocked on client level. So it's useful to have this info available.

If we decide on making any change then I will make these changes in the next PR because this PR is just doing refactoring.

Comment on lines 51 to 66
* 'parsely' => array(
* array(
* 'org' => array( 'status' => 'blocked' ),
* 'env' => array(
* 'status' => 'enabled',
* 'config' => array(),
* ),
* 'network_sites' => array (
* 1 => array (
* 'status' => 'disabled',
* 'config' => array(),
* ),
* 2 => array (
* 'status' => 'enabled',
* 'config' => array(),
* ),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it's just an example, but I think this is surfacing in the code as a result so wanted to point out here too.

Nothing blocked at the org level should ever make it to the WP site. There's no scenario where we will block on org but enable on env. If blocked at org level or site level, then that should mean the configmap will never see an entry for that integration. It doesn't exist at all.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out. Fixed the example in fe14e06

As per current implementation if the integration is blocked on org level then we don't include any data from site level integration even if there is data.

// Example

<?php

return array(
  'parsely' => array(
    array(
      'org'  => array( 'status' => 'blocked' ),
    ),
  ),
);

Comment on lines +250 to +253
// Look for key inside org or env config.
if ( 'network_sites' !== $config_type && isset( $vip_config[ $config_type ][ $key ] ) ) {
return $vip_config[ $config_type ][ $key ];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not even sure if we need to concept of org configs down at this level either.

When generating configmaps, we're already dealing with only one specific environment. So we can decide what the configs are for that particular environment (based on higher levels if needed), and pass down the resulting env configs along with network site configs if it's a MS.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently from code point of view we do support having config on org level but in actual we don't have any config from ConfigMap so feel free to let me know if you like me to add a condition here which throws the error if config is provided on org level. Personally I think it is fine as it is.

}

// Return config object if integration have only one config else return all configs.
return ( ! $this->have_multiple_setups && isset( $configs[0] ) ) ? $configs[0] : $configs;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some nice benefits to having individual sources be able to cascade down with their own configs like the other integrations. Helps prevent duplication for network sites for example, and keeps things logically operating the same way.

* @private
*/
public function is_active_via_vip(): bool {
return in_array( Env_Integration_Status::ENABLED, $this->get_site_statuses() );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think we absolutely need the concept of a parent integration present here. The parent should be the one deciding if the whole thing should be enabled (and at what version) for the env/subsite.

Copy link

sonarcloud bot commented Aug 22, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants