08_tenant_migration/
08_tenant_migration.rs1use std::sync::Arc;
13use tokio::sync::RwLock;
14use wami::arn::{TenantPath, WamiArn};
15use wami::context::WamiContext;
16use wami::service::{GroupService, TenantService, UserService};
17use wami::store::memory::InMemoryWamiStore;
18use wami::wami::identity::group::requests::CreateGroupRequest;
19use wami::wami::identity::user::requests::{CreateUserRequest, ListUsersRequest};
20use wami::wami::tenant::model::TenantId;
21
22#[tokio::main]
23async fn main() -> Result<(), Box<dyn std::error::Error>> {
24 println!("=== Tenant Migration ===\n");
25
26 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
27
28 let root_context = WamiContext::builder()
30 .instance_id("123456789012")
31 .tenant_path(TenantPath::single(0))
32 .caller_arn(
33 WamiArn::builder()
34 .service(wami::arn::Service::Iam)
35 .tenant_path(TenantPath::single(0))
36 .wami_instance("123456789012")
37 .resource("user", "admin")
38 .build()?,
39 )
40 .is_root(true)
41 .build()?;
42
43 let old_tenant_context = WamiContext::builder()
45 .instance_id("123456789012")
46 .tenant_path(TenantPath::single(80000000))
47 .caller_arn(
48 WamiArn::builder()
49 .service(wami::arn::Service::Iam)
50 .tenant_path(TenantPath::single(80000000))
51 .wami_instance("123456789012")
52 .resource("user", "admin")
53 .build()?,
54 )
55 .is_root(false)
56 .build()?;
57
58 let new_tenant_context = WamiContext::builder()
60 .instance_id("123456789012")
61 .tenant_path(TenantPath::single(90000000))
62 .caller_arn(
63 WamiArn::builder()
64 .service(wami::arn::Service::Iam)
65 .tenant_path(TenantPath::single(90000000))
66 .wami_instance("123456789012")
67 .resource("user", "admin")
68 .build()?,
69 )
70 .is_root(false)
71 .build()?;
72
73 println!("Step 1: Creating source and destination tenants...\n");
75
76 let tenant_service = TenantService::new(store.clone());
77
78 let _old_tenant_id = TenantId::from_string("80000000").unwrap();
79 tenant_service
80 .create_tenant(
81 &root_context,
82 "old-tenant".to_string(),
83 Some("Old Tenant (deprecated)".to_string()),
84 None,
85 )
86 .await?;
87 println!("✓ Created source tenant: old-tenant");
88
89 let _new_tenant_id = TenantId::from_string("90000000").unwrap();
90 tenant_service
91 .create_tenant(
92 &root_context,
93 "new-tenant".to_string(),
94 Some("New Tenant (target)".to_string()),
95 None,
96 )
97 .await?;
98 println!("✓ Created destination tenant: new-tenant");
99
100 println!("\nStep 2: Creating resources in old tenant...\n");
102
103 let user_service = UserService::new(store.clone());
104 let group_service = GroupService::new(store.clone());
105
106 let user_req = CreateUserRequest {
108 user_name: "bob".to_string(),
109 path: Some("/users/".to_string()),
110 permissions_boundary: None,
111 tags: None,
112 };
113 let old_user = user_service
114 .create_user(&old_tenant_context, user_req)
115 .await?;
116 println!("✓ Created user in old-tenant:");
117 println!(" - Name: {}", old_user.user_name);
118 println!(" - ARN: {}", old_user.arn);
119
120 let group_req = CreateGroupRequest {
122 group_name: "developers".to_string(),
123 path: Some("/groups/".to_string()),
124 tags: None,
125 };
126 let old_group = group_service
127 .create_group(&old_tenant_context, group_req)
128 .await?;
129 println!("\n✓ Created group in old-tenant:");
130 println!(" - Name: {}", old_group.group_name);
131 println!(" - ARN: {}", old_group.arn);
132
133 group_service
135 .add_user_to_group(&old_tenant_context, "developers", "bob")
136 .await?;
137 println!("\n✓ Added bob to developers group in old-tenant");
138
139 println!("\n\nStep 3: Migrating resources to new tenant...\n");
141
142 println!("Migrating user...");
144 let new_user_req = CreateUserRequest {
145 user_name: old_user.user_name.clone(),
146 path: Some(old_user.path.clone()),
147 permissions_boundary: old_user.permissions_boundary.clone(),
148 tags: Some(old_user.tags.clone()),
149 };
150 let new_user = user_service
151 .create_user(&new_tenant_context, new_user_req)
152 .await?;
153 println!("✓ Re-created user in new-tenant:");
154 println!(" - Old ARN: {}", old_user.arn);
155 println!(" - New ARN: {}", new_user.arn);
156
157 println!("\nMigrating group...");
159 let new_group_req = CreateGroupRequest {
160 group_name: old_group.group_name.clone(),
161 path: Some(old_group.path.clone()),
162 tags: Some(old_group.tags.clone()),
163 };
164 let new_group = group_service
165 .create_group(&new_tenant_context, new_group_req)
166 .await?;
167 println!("✓ Re-created group in new-tenant:");
168 println!(" - Old ARN: {}", old_group.arn);
169 println!(" - New ARN: {}", new_group.arn);
170
171 println!("\nRestoring group membership...");
173 group_service
174 .add_user_to_group(&new_tenant_context, "developers", "bob")
175 .await?;
176 println!("✓ Re-added bob to developers group in new-tenant");
177
178 println!("\n\nStep 4: Cleaning up old tenant (optional)...\n");
180
181 println!("In production, you would:");
182 println!("- Remove user from old group");
183 println!("- Delete user from old tenant");
184 println!("- Delete group from old tenant");
185 println!("- Audit all resource references");
186 println!("- Update application configurations");
187
188 println!("\n(Cleanup skipped for demonstration purposes)");
193
194 println!("\n\nStep 5: Verifying migration...\n");
196
197 let (old_users, _, _) = user_service
198 .list_users(
199 &old_tenant_context,
200 ListUsersRequest {
201 path_prefix: Some("/users/".to_string()),
202 pagination: None,
203 },
204 )
205 .await?;
206 println!("Users remaining in old-tenant: {}", old_users.len());
207
208 let (new_users, _, _) = user_service
209 .list_users(
210 &new_tenant_context,
211 ListUsersRequest {
212 path_prefix: Some("/users/".to_string()),
213 pagination: None,
214 },
215 )
216 .await?;
217 println!("Users now in new-tenant: {}", new_users.len());
218 for user in &new_users {
219 println!(" - {}", user.user_name);
220 }
221
222 println!("\n✅ Example completed successfully!");
223 println!("Key takeaways:");
224 println!("- Tenant migration requires re-creating resources in the target tenant");
225 println!("- ARNs change when resources move between tenants");
226 println!("- Preserve metadata (tags, paths) during migration");
227 println!("- Update all references after migration");
228 println!("- Consider phased migration for large-scale moves");
229
230 Ok(())
231}