When configuring an SSIS package, you have 3 options: use design time values, manually edit values and use an Environment.
Approach 1
I have found success with a mixture of the last two. I create a folder: Configuration and a single Environment, Settings. No projects are deployed to Configuration.
I fill the Settings environment with anything that is likely to be shared across projects. Data base connection strings, ftp users and passwords, common file processing locations, etc.
Per deployed project, the things we find we need to configure are handled through explicit overrides. For example, the file name changes by environment so we'd have set the value via the editor but instead of clicking OK, we click the Script button up on top. That generates a call like
DECLARE @var sql_variant = N'DEV_Transpo*.txt';
EXEC SSISDB.catalog.set_object_parameter_value
@object_type = 20
, @parameter_name = N'FileMask'
, @object_name = N'LoadJobCosting'
, @folder_name = N'Accounting'
, @project_name = N'Costing'
, @value_type = V
, @parameter_value = @var;
We store the scripts and run them as part of the migration. It's lead to some scripts looking like
SELECT @var = CASE @@SERVERNAME
WHEN 'SQLSSISD01' THEN N'DEV_Transpo*.txt'
WHEN 'SQLSSIST01' THEN N'TEST_Transpo*.txt'
WHEN 'SQLSSISP01' THEN N'PROD_Transpo*.txt'
END
But it's a one time task so I don't think it's onerous. The assumption with how our stuff works is that it's pretty static, once we get it figured out, so there's not much churn once it's working. Rarely do the vendors redefine their naming standards.
Approach 2
If you find that approach unreasonable, then perhaps resume using a table for configuration of the dynamic-ish stuff. I could see two implementations working on that.
Option A
The first is set from an external actor. Basically, the configuration step from above but instead of storing the static scripts, a simple cursor will go an apply them.
--------------------------------------------------------------------------------
-- Set up
--------------------------------------------------------------------------------
CREATE TABLE dbo.OptionA
(
FolderName sysname
, ProjectName sysname
, ObjectName sysname
, ParameterName sysname
, ParameterValue sql_variant
);
INSERT INTO
dbo.OptionA
(
FolderName
, ProjectName
, ObjectName
, ParameterName
, ParameterValue
)
VALUES
(
'MyFolder'
, 'MyProject'
, 'MyPackage'
, 'MyParameter'
, 100
);
INSERT INTO
dbo.OptionA
(
FolderName
, ProjectName
, ObjectName
, ParameterName
, ParameterValue
)
VALUES
(
'MyFolder'
, 'MyProject'
, 'MyPackage'
, 'MySecondParameter'
, 'Foo'
);
The above simply creates a table that identifies all the configurations that should be applied and where they should go.
--------------------------------------------------------------------------------
-- You might want to unconfigure anything that matches the following query.
-- Use cursor logic from below substituting this as your source
--SELECT
-- *
--FROM
-- SSISDB.catalog.object_parameters AS OP
--WHERE
-- OP.value_type = 'V'
-- AND OP.value_set = CAST(1 AS bit);
--
-- Use the following method to remove existing configurations
-- in place of adding them
--
--EXECUTE SSISDB.catalog.clear_object_parameter_value
-- @folder_name = @FolderName
-- @project_name = @ProjectName
-- @object_type = 20
-- @object_name = @ObjectName
-- @parameter_name = @ParameterName
--------------------------------------------------------------------------------
Thus begins the application of configurations
--------------------------------------------------------------------------------
-- Apply configurations
--------------------------------------------------------------------------------
DECLARE
@ProjectName sysname
, @FolderName sysname
, @ObjectName sysname
, @ParameterName sysname
, @ParameterValue sql_variant;
DECLARE Csr CURSOR
READ_ONLY FOR
SELECT
OA.FolderName
, OA.ProjectName
, OA.ObjectName
, OA.ParameterName
, OA.ParameterValue
FROM
dbo.OptionA AS OA
OPEN Csr;
FETCH NEXT FROM Csr INTO
@ProjectName
, @FolderName
, @ObjectName
, @ParameterName
, @ParameterValue;
WHILE (@@fetch_status <> -1)
BEGIN
IF (@@fetch_status <> -2)
BEGIN
EXEC SSISDB.catalog.set_object_parameter_value
-- 20 = project
-- 30 = package
@object_type = 30
, @folder_name = @FolderName
, @project_name = @ProjectName
, @parameter_name = @ParameterName
, @parameter_value = @ParameterValue
, @object_name = @ObjectName
, @value_type = V;
END
FETCH NEXT FROM Csr INTO
@ProjectName
, @FolderName
, @ObjectName
, @ParameterName
, @ParameterValue;
END
CLOSE Csr;
DEALLOCATE Csr;
When do you run this? Whenever it needs to be run. You could set up a trigger on OptionA to keep this tightly in sync or make it as part of the post deploy process. Really, whatever makes sense in your organization.
Option B
This is going be much along the lines of Vinnie's suggestion. I would design a Parent/Orchestrator package that is responsible for finding all the possible configurations for the project and then populate variables. Then, make use of the cleaner variable passing for child packages with the project deployment model.
Personally, I don't care for that approach as it puts more responsibility on the developers that implement the solution to get the coding right. I find it has a higher cost of maintenance and not all BI developers are comfortable with code. And that script needs to be implemented across a host of parent type packages and tends to lead to copy and paste inheritance and nobody likes that.