A weekly schedule of running windows for a SQL Managed Instance, so it is billed only while it is needed — targeting
hashicorp/azurerm ~> 4.0.
- ⏰ Records the weekly windows in which a SQL Managed Instance runs — everything outside them is downtime.
- 🧮 Computes and emits the running and stopped hours per week, because that number is the decision and nobody derives it reliably by hand.
- ⌛ Enforces the
HH:MMformat the provider does not check at all. ⚠️ States the fact that catches everyone: the times are when the operation is initiated, not when the instance is ready.- 🔕 Reports that a stop can be silently skipped, so a saving forecast is an upper bound.
💡 Why it matters: the schedule is not a set of maintenance events layered onto a running instance — it is the instance's uptime. A single Monday-to-Friday window means every database is unreachable all weekend. Applying this to an instance that currently runs continuously will take it offline at the first gap, which is the feature working correctly and is rarely what a reader expects on first reading.
If this module saved you time:
- ⭐ Star the repository
- 💼 Connect on LinkedIn
- ☕ Buy me a coffee
flowchart TB
MI["terraform-azurerm-mssql-managed-instance"]
THIS["terraform-azurerm-mssql-managed-instance-start-stop-schedule"]
FOG["terraform-azurerm-mssql-managed-instance-failover-group"]
ADM["terraform-azurerm-mssql-managed-instance-active-directory-administrator"]
TDE["terraform-azurerm-mssql-managed-instance-transparent-data-encryption"]
SRV["terraform-azurerm-mssql-server"]
MI -->|"id"| THIS
MI -->|"id"| FOG
MI -->|"id"| ADM
MI -->|"id"| TDE
THIS -.->|"a stopped instance serves no failover role"| FOG
SRV -.->|"logical servers cannot be stopped this way"| THIS
style THIS fill:#0078D4,stroke:#004578,color:#ffffff
style MI fill:#004578,stroke:#004578,color:#ffffff
style FOG fill:#F3F2F1,stroke:#8A8886,color:#201F1E
style ADM fill:#F3F2F1,stroke:#8A8886,color:#201F1E
style TDE fill:#F3F2F1,stroke:#8A8886,color:#201F1E
style SRV fill:#F3F2F1,stroke:#8A8886,color:#201F1E
Every module in this family takes the same managed instance's id; this one differs in what it does with it.
The dotted edge to the failover group is the interaction worth thinking about before combining them — a
stopped instance is not serving any failover role, so a schedule and a disaster-recovery pairing on the same
instance are two controls with opposite assumptions. The other dotted edge is a reminder that a logical SQL
server cannot be stopped this way at all.
flowchart TB
MID["managed_instance_id (required, force-new)"]
SCH["schedule (required, at least one running window)"]
TZ["timezone_id (Windows zone, defaults to UTC)"]
SS["azurerm_mssql_managed_instance_start_stop_schedule.this"]
OID["id"]
ORUN["running_hours_per_week"]
OSTOP["stopped_hours_per_week"]
ONEXT["next_execution_time"]
MID --> SS
SCH --> SS
TZ --> SS
SS --> OID
SS --> ORUN
SS --> OSTOP
SS --> ONEXT
style SS fill:#0078D4,stroke:#004578,color:#ffffff
style SCH fill:#004578,stroke:#004578,color:#ffffff
style MID fill:#F3F2F1,stroke:#8A8886,color:#201F1E
style TZ fill:#F3F2F1,stroke:#8A8886,color:#201F1E
style OID fill:#F3F2F1,stroke:#8A8886,color:#201F1E
style ORUN fill:#F3F2F1,stroke:#8A8886,color:#201F1E
style OSTOP fill:#F3F2F1,stroke:#8A8886,color:#201F1E
style ONEXT fill:#F3F2F1,stroke:#8A8886,color:#201F1E
| Resource | Count | Notes |
|---|---|---|
azurerm_mssql_managed_instance_start_stop_schedule.this |
1 | One per instance; the Resource ID always ends /startStopSchedules/default |
| Requirement | Value |
|---|---|
| Terraform | >= 1.12.0 |
hashicorp/azurerm |
~> 4.0 |
| Provider block | None in this module — the caller configures the provider, its auth, and the mandatory features {} block |
Schema notes that bite:
- 🔴 The times are when the operation is INITIATED, not when the instance is ready. Microsoft's worked example: to be available at 8 AM, schedule the start at 7:40 AM.
- 🔴 The provider applies no time-format check.
start_timeandstop_timecarry only a non-empty check, so9am,09:00:00and25:00all pass its validation and fail at Azure. TheHH:MMrule here is the module's. - 🔴 Microsoft documents two rules the provider does not enforce: scheduled pairs may not overlap, and any two successive actions must be at least one hour apart. The API rejects violations at apply. This module refuses the unambiguous cases and reports the rest.
- 🔴 A stop can be silently skipped. If a conflicting operation is in progress, Azure retries after ten minutes and then abandons that occurrence — the instance keeps running and nothing reports it.
- 🔴 General Purpose tier only. A Business Critical instance cannot be stopped, and this module receives only a Resource ID.
⚠️ schedulecarries a minimum of one item, invisible in the binary schema — an empty list fails with "Not enough list items".⚠️ The day names are a closed, CASE-SENSITIVE set:mondayandMONDAYare both refused.⚠️ timezone_idis a WINDOWS identifier, not IANA —Central Europe Standard Time, notEurope/Berlin. The provider checks only non-emptiness.- ℹ️ There IS a requires-import guard on create, so a clean apply is evidence no schedule existed.
- ℹ️ Delete removes the schedule and leaves the instance where it is — including stopped, with nothing left to start it.
- ℹ️ No
tags, nolocation. All four timeouts are honoured (30/5/30/30) and govern writing the schedule, not running it.
| Permission | Scope | Why |
|---|---|---|
Microsoft.Sql/managedInstances/startStopSchedules/read and /write |
the managed instance | create, update and delete the schedule |
SQL Managed Instance Contributor (or Contributor) |
the managed instance | the built-in role carrying the above |
🔴 Whoever can write this resource can take every database on the instance offline, on a recurring basis, by editing four strings. It is a smaller-looking permission than it is.
ℹ️ No data-plane permission is involved. The schedule is control-plane metadata and says nothing about who may read the databases while they are up.
- The
Microsoft.Sqlresource provider registered on the subscription. - An existing SQL Managed Instance in the General Purpose service tier. Business Critical instances cannot be stopped.
- A decision about the Windows time zone —
UTCis the default and the only one that does not shift twice a year. - The caller configures
provider "azurerm" { features {} }, auth and subscription.
terraform-azurerm-mssql-managed-instance-start-stop-schedule/
├── providers.tf # required_version + pinned azurerm; no provider block
├── variables.tf # 5 inputs, deeply typed, with the format and timing rules
├── main.tf # the single keystone `this`
├── outputs.tf # id first, then the computed weekly hours, then the posture facts
├── README.md # this file
├── SCOPE.md # the cross-module contract
├── LICENSE # MIT
└── .gitignore
provider "azurerm" {
features {}
}
module "sqlmi_schedule" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-mssql-managed-instance-start-stop-schedule.git?ref=v1.0.0"
managed_instance_id = module.sqlmi_dev.id
schedule = [
{
start_day = "Monday"
start_time = "07:40"
stop_day = "Friday"
stop_time = "19:00"
},
]
}That instance is now stopped from Friday evening until Monday morning — about 60 hours a week. Read example 1 before applying it to anything that currently runs continuously.
Consumes
| Input | Type | Source |
|---|---|---|
managed_instance_id |
Resource ID | terraform-azurerm-mssql-managed-instance → id |
schedule |
list(object) |
the caller |
timezone_id |
Windows zone name | the caller |
Emits
| Output | Description |
|---|---|
id |
Resource ID of the schedule (first) |
running_hours_per_week / stopped_hours_per_week |
the numbers the decision turns on |
running_windows |
the windows as readable strings |
next_execution_time / next_run_action |
the service's own interpretation |
this_schedule_never_stops_the_instance |
true when the windows cover the week |
1 · A working-week schedule, and what it costs in availability
module "sqlmi_schedule" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-mssql-managed-instance-start-stop-schedule.git?ref=v1.0.0"
managed_instance_id = module.sqlmi_dev.id
schedule = [
{
start_day = "Monday"
start_time = "07:40"
stop_day = "Friday"
stop_time = "19:00"
},
]
}
output "uptime" {
value = {
running = module.sqlmi_schedule.running_hours_per_week # 107.33
stopped = module.sqlmi_schedule.stopped_hours_per_week # 60.66
}
}🔴 Every hour outside a window is downtime. This instance is unreachable all weekend — that is the feature, and it is why the module computes the hours rather than leaving them to be inferred from four strings.
⚠️ Applying this to an instance that currently runs continuously takes it offline at the first gap.
2 · The forty-minute head start
schedule = [
{
start_day = "Monday"
start_time = "07:40" # so the instance is UP by 08:00
stop_day = "Friday"
stop_time = "19:00"
},
]🔴 Scheduled items are when the start and stop actions are INITIATED, not when the instance is up and running. That is Microsoft's own wording, and their worked example is exactly this: schedule the start at 7:40 AM if you want the instance available at 8 AM.
⚠️ A schedule written as though the times were availability windows will have the instance still starting when the working day begins — and nothing in Terraform or Azure will flag it.
3 · Several windows in one week
module "sqlmi_schedule" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-mssql-managed-instance-start-stop-schedule.git?ref=v1.0.0"
managed_instance_id = module.sqlmi_dev.id
schedule = [
{
start_day = "Monday"
start_time = "07:40"
stop_day = "Friday"
stop_time = "19:00"
},
{
start_day = "Saturday"
start_time = "08:00"
stop_day = "Saturday"
stop_time = "12:00"
},
]
}
output "windows" {
# ["Monday 07:40 -> Friday 19:00", "Saturday 08:00 -> Saturday 12:00"]
value = module.sqlmi_schedule.running_windows
}ℹ️ The windows render in the order given. This module does not sort them — sorting would produce a plan diff when only the author's arrangement had changed.
⚠️ Microsoft forbids overlapping pairs and the API rejects them. This module does not attempt overlap detection, because it would need a week ordering the service does not publish; hours summing past 168 is the hint, andthis_schedule_never_stops_the_instancecatches the extreme case.
4 · The format the provider does not check
# ALL REFUSED at plan by this module -- and ALL accepted by the provider:
# start_time = "9am"
# start_time = "09:00:00"
# start_time = "25:00"
# start_time = "09:60"
#
# Correct:
schedule = [
{ start_day = "Monday", start_time = "09:00", stop_day = "Monday", stop_time = "17:00" },
]🔴
start_timeandstop_timecarry only a non-empty check in the provider, so every one of those values passesterraform validateon a bare resource and fails at Azure. TheHH:MMrule is the module's, taken from Microsoft's own examples.ℹ️ The day names are checked by the provider, against a closed case-sensitive set —
mondayis refused there too.
5 · The one-hour rule, where it can be judged
# REFUSED -- same day, 30 minutes apart:
# { start_day = "Monday", start_time = "09:00", stop_day = "Monday", stop_time = "09:30" }
#
# ACCEPTED -- exactly one hour:
schedule = [
{ start_day = "Monday", start_time = "09:00", stop_day = "Monday", stop_time = "10:00" },
]
⚠️ Microsoft requires at least one hour between any two successive start and stop actions, and the API rejects a shorter gap.💡 This module refuses only the unambiguous same-day case. A window whose stop falls earlier than its start may be crossing the week boundary, and judging it would need a day ordering the service does not publish — so those are listed in
cross_day_windows_are_not_checked_against_the_one_hour_rulerather than guessed at.
6 · Time zones, and the one that moves
module "sqlmi_schedule" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-mssql-managed-instance-start-stop-schedule.git?ref=v1.0.0"
managed_instance_id = module.sqlmi_dev.id
timezone_id = "Eastern Standard Time" # a WINDOWS identifier
schedule = [
{ start_day = "Monday", start_time = "07:40", stop_day = "Friday", stop_time = "19:00" },
]
}🔴
Europe/BerlinandAmerica/New_Yorkare IANA names and are refused here — Azure wants Windows identifiers. That is the one mistake this module catches; any other string is passed through, because the full Windows list is not published by the provider.
⚠️ A zone observing daylight saving moves the schedule twice a year relative to UTC.UTCis the default because it does not — which makes it predictable and makes it the wrong choice if the point is to match an office's working day. Decide which you want.
7 · Checking what the service thinks the schedule means
output "service_interpretation" {
value = {
next_at = module.sqlmi_schedule.next_execution_time
next_action = module.sqlmi_schedule.next_run_action
}
}💡 These are read back from Azure, not computed here. They are the honest way to confirm a schedule means what its author intended — particularly across a time-zone choice or a window that crosses midnight, where the module's own hour arithmetic rests on a stated assumption.
8 · A schedule that saves nothing
output "pointless" {
value = module.sqlmi_schedule.this_schedule_never_stops_the_instance
}
⚠️ A schedule whose windows cover the whole week is legal and expensive. It implies a cost control while providing none, and it is easy to arrive at by adding windows one at a time. The flag catches it before someone reports a saving that never existed.
9 · Why the saving is an upper bound
output "forecast_caveat" {
value = {
stopped_hours = module.sqlmi_schedule.stopped_hours_per_week
may_be_skipped = module.sqlmi_schedule.a_stop_can_be_silently_skipped
}
}🔴 A stop can be silently skipped. Microsoft documents that if a conflicting operation — a vCore scaling, for instance — is in progress when a stop is triggered, the mechanism retries after ten minutes and then abandons that occurrence. The instance keeps running, and nothing in Terraform reports it.
💡 So
stopped_hours_per_weekis the maximum saving, not the expected one.
10 · Saying why, in the only field that can
module "sqlmi_schedule" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-mssql-managed-instance-start-stop-schedule.git?ref=v1.0.0"
managed_instance_id = module.sqlmi_dev.id
description = "Dev instance: deliberately off nights and weekends. Do not extend without asking the data team."
schedule = [
{ start_day = "Monday", start_time = "07:40", stop_day = "Friday", stop_time = "19:00" },
]
}💡 A schedule is a set of times with no explanation attached. The next person to read it will want to know whether the weekend gap is deliberate cost saving or an oversight — and
descriptionis the only place in the resource that can answer.
11 · A schedule and a failover group on the same instance
module "sqlmi_schedule" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-mssql-managed-instance-start-stop-schedule.git?ref=v1.0.0"
managed_instance_id = module.sqlmi_dev.id # a DEV instance, not the DR secondary
schedule = [
{ start_day = "Monday", start_time = "07:40", stop_day = "Friday", stop_time = "19:00" },
]
}
⚠️ Think carefully before scheduling an instance that is part of a failover group. A stopped instance is not serving any disaster-recovery role, so a schedule on a DR secondary quietly removes the protection the failover group exists to provide — for most of the week.💡 Schedules belong on development and test instances. That is the case this module is built around.
12 · Several instances from one map
module "sqlmi_schedule" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-mssql-managed-instance-start-stop-schedule.git?ref=v1.0.0"
for_each = module.dev_instances
managed_instance_id = each.value.id
description = "Non-production: off outside working hours"
schedule = [
{ start_day = "Monday", start_time = "07:40", stop_day = "Friday", stop_time = "19:00" },
]
}
output "weekly_stopped_hours" {
value = { for k, m in module.sqlmi_schedule : k => m.stopped_hours_per_week }
}
output "any_saving_nothing" {
value = [for k, m in module.sqlmi_schedule : k if m.this_schedule_never_stops_the_instance]
}💡 Keying by a stable name means adding or removing an instance never re-indexes the rest, and the first output turns a fleet-wide cost question into one map.
13 · 🏗️ End-to-end composition
provider "azurerm" {
features {}
}
data "azurerm_client_config" "current" {}
module "sqlmi_dev" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-mssql-managed-instance.git?ref=v1.0.0"
name = "sqlmi-dev-eus2"
resource_group_name = "rg-data-dev"
location = "eastus2"
# General Purpose -- stop and start is not available on Business Critical.
sku_name = "GP_Gen5"
vcores = 4
storage_size_in_gb = 256
subnet_id = var.dev_subnet_id
license_type = "BasePrice"
# Both are required through this module: the provider pairs each with an
# inline Entra administrator block that this module does not expose.
administrator_login = "sqladmin"
administrator_login_password = var.mi_admin_password # out of band; never committed
}
module "sqlmi_dev_entra_admin" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-mssql-managed-instance-active-directory-administrator.git?ref=v1.0.0"
managed_instance_id = module.sqlmi_dev.id
login_username = "sql-mi-admins"
object_id = var.sql_admin_group_object_id
tenant_id = data.azurerm_client_config.current.tenant_id
}
module "sqlmi_schedule" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-mssql-managed-instance-start-stop-schedule.git?ref=v1.0.0"
managed_instance_id = module.sqlmi_dev.id
timezone_id = "UTC"
description = "Dev instance: off nights and weekends to control cost"
schedule = [
{
start_day = "Monday"
start_time = "07:40" # up by 08:00
stop_day = "Friday"
stop_time = "19:00"
},
]
}
output "dev_instance_cost_posture" {
value = {
running_hours = module.sqlmi_schedule.running_hours_per_week
stopped_hours = module.sqlmi_schedule.stopped_hours_per_week
fraction_up = module.sqlmi_schedule.running_fraction_of_week
windows = module.sqlmi_schedule.running_windows
next_action_at = module.sqlmi_schedule.next_execution_time
saving_is_a_max = module.sqlmi_schedule.a_stop_can_be_silently_skipped
}
}💡 A General Purpose development instance is the case this module is built around — the tier is stated in the composition because Business Critical instances cannot be stopped at all.
⚠️ The Entra administrator is configured independently of the schedule, and it keeps working across stops and starts. Nothing about a stopped instance changes who administers it.🔴 The instance is unreachable roughly 60 hours a week under this schedule. That is the intent; make sure everything that runs against it — backups, agent jobs, CI pipelines — expects it.
Identity — managed_instance_id (required, force-new).
Windows — schedule (required, at least one).
Interpretation — timezone_id, description.
Tail — timeouts. (There is no tags: the resource exposes none.)
Full schemas
| Name | Type | Default | Notes |
|---|---|---|---|
managed_instance_id |
string |
— | Required, force-new. Anchored; a logical server ID is refused. |
schedule |
list(object({start_day, start_time, stop_day, stop_time})) |
— | Required, min 1. Days case-sensitive; times HH:MM, enforced by the module. |
timezone_id |
string |
"UTC" |
A Windows zone name. IANA names refused. |
description |
string |
null |
The only place to record why. |
timeouts |
object({create, read, update, delete}) |
null |
All four real; they govern writing the schedule, not running it. |
| Output | Description |
|---|---|
id |
Resource ID of the schedule (first) |
managed_instance_id / managed_instance_name / resource_group_name / subscription_id |
the parent |
timezone_id |
as configured |
running_windows |
the windows as readable strings |
schedule_item_count |
how many windows |
running_hours_per_week / stopped_hours_per_week |
the computed weekly figures |
running_fraction_of_week |
a proxy for the compute saving |
next_execution_time / next_run_action |
the service's own interpretation |
creating_this_resource_stops_a_database |
constant true |
the_times_are_when_the_operation_starts_not_when_it_finishes |
constant true |
this_schedule_never_stops_the_instance |
true when the windows cover the week |
cross_day_windows_are_not_checked_against_the_one_hour_rule |
what the module could not judge |
overlapping_windows_are_rejected_by_azure_not_by_this_module |
constant true |
the_provider_applies_no_time_format_check |
constant true |
a_stop_can_be_silently_skipped |
constant true |
this_feature_is_general_purpose_tier_only |
constant true |
stopping_is_a_billing_control_not_a_restart |
constant true |
the_time_zone_applies_to_every_window |
constant true |
a_daylight_saving_zone_moves_the_schedule_twice_a_year |
constant true |
an_existing_schedule_blocks_creation |
constant true |
destroying_this_resource_leaves_the_instance_running |
constant true |
one_schedule_per_managed_instance |
constant true |
force_new_fields / fields_that_can_change_after_creation |
lifecycle |
fields_azure_returns_on_read |
where drift is detectable |
all_four_timeouts_are_honoured_here |
constant true |
this_resource_supports_no_azure_resource_tags |
constant true |
🔒 No secret is accepted or emitted: this resource records times.
The windows are the uptime. That is the single idea this module is built around. A schedule entry is
not a maintenance event layered onto a running instance — the instance runs between the start and the stop
and is stopped the rest of the time. So the module computes running_hours_per_week and
stopped_hours_per_week and puts them in front of the reader, because the hours are the decision and a list
of four-field objects is not a good way to see them.
Those figures rest on a stated assumption. Week-minutes are computed with Monday as the first day, and a
window whose stop falls at or before its start is treated as crossing the week boundary. The service does not
publish an ordering, so the output descriptions say so and point at next_execution_time — which is Azure's
own answer — as the way to check.
Two rules are enforced that the provider does not check at all. The HH:MM format comes from Microsoft's
examples, not from a provider validator, and the error message says so. Microsoft's one-hour minimum between
successive actions is enforced only for unambiguous same-day windows, because judging a window that may
wrap the week would require the ordering the service does not publish. The rest are listed in an output
rather than guessed at — the module says what it could not check.
Overlap is left to Azure. Microsoft forbids overlapping pairs and the API rejects them, but reliable
detection needs the same unpublished ordering. running_hours_per_week summing past 168 is the practical
hint, and this_schedule_never_stops_the_instance catches the extreme case.
The saving is an upper bound, not a forecast. A stop is skipped entirely if a conflicting operation is
still running ten minutes later, and nothing reports that. Any cost model built on stopped_hours_per_week
should be read as the best case.
Nothing is inverted here. timezone_id keeps the provider's UTC, which is the predictable choice; and
there is no default schedule, because there is no safe one — a schedule is by definition downtime, so it must
be typed.
Destroy is the reassuring direction. Deleting the schedule removes the schedule and nothing else: the instance stays in whatever state it is in. A destroy performed while the instance is stopped leaves it stopped, with nothing scheduled to start it again — worth knowing before doing it on a Friday.
| Concern | Secure default (empty call) | Opt-out (caller must type it) |
|---|---|---|
| The schedule itself | no default — downtime is always explicit | — |
| Time zone | UTC — the only zone that does not shift twice a year |
a Windows zone name |
| Time format | HH:MM enforced, though the provider checks nothing |
— |
| One-hour rule | enforced where unambiguous, reported where it is not | — |
| Overlap | left to Azure, and said so | — |
| Window ordering | preserved as written, never sorted | — |
| Secret handling | none — this resource records times | not available |
terraform init -backend=false
terraform validate
terraform fmt -checkPin the module with ?ref=v1.0.0 — never a branch. This module is plan-only in this repository; a human
applies from CI.
terraform validate proves, offline and with no credentials: the anchored managed_instance_id pattern, the
at-least-one-window rule, the closed case-sensitive day set, the HH:MM format on both times, the
zero-length-window refusal, the same-day one-hour minimum, the IANA-time-zone refusal, and the
whitespace-only description refusal.
Only terraform plan and apply exercise: whether the instance exists, whether it is General Purpose, and
whether Azure accepts the windows as non-overlapping.
Nothing at either stage tells you that a stop was skipped, or that the instance is down when someone needs
it. That is what next_execution_time, the computed hours and the constant outputs are for.
Note the asymmetry: a validation failure blocks terraform destroy as well as apply, which is why the
timing checks are narrowed to the cases that cannot be legal rather than applied to every window.
id = "/subscriptions/.../resourceGroups/rg-data-dev/providers/Microsoft.Sql/managedInstances/sqlmi-dev-eus2/startStopSchedules/default"
managed_instance_name = "sqlmi-dev-eus2"
timezone_id = "UTC"
running_windows = ["Monday 07:40 -> Friday 19:00"]
schedule_item_count = 1
running_hours_per_week = 107.33
stopped_hours_per_week = 60.66
running_fraction_of_week = 0.6388888888888888
next_execution_time = "2026-08-17T07:40:00Z"
next_run_action = "Start"
force_new_fields = ["managed_instance_id"]
| Symptom | Cause | Fix |
|---|---|---|
a schedule entry has a start_time or stop_time that is not HH:MM |
9am, 09:00:00, 25:00 or similar |
Use 24-hour HH:MM. The provider accepts these and fails at Azure; this check is the module's |
a schedule entry has a start_day or stop_day outside the closed set |
wrong case or an abbreviation | Monday, not monday or Mon |
schedule must contain at least one window |
an empty list | The provider requires at least one item |
a schedule entry starts and stops at the same moment |
identical day and time | Give the instance a period to run in |
a schedule entry starts and stops on the same day less than an hour apart |
under Microsoft's one-hour minimum | Widen the window |
timezone_id looks like an IANA time zone |
Europe/Berlin or similar |
Use the Windows name — W. Europe Standard Time |
| Azure rejects the schedule as overlapping | Microsoft forbids overlapping pairs; this module does not detect it | Check running_windows and whether the hours sum past 168 |
| The instance was still starting when the working day began | the times are when the operation is initiated | Move the start earlier — Microsoft's example is 20 minutes |
| The instance did not stop when it should have | a conflicting operation was in progress; Azure retried once and skipped it | Expected. Nothing reports it, and the saving is an upper bound |
| Apply fails and the instance is Business Critical | stop and start is a General Purpose capability | This module cannot see the tier; the failure appears at apply |
| The schedule ran an hour early or late after a clock change | the time zone observes daylight saving | Expected. Use UTC if predictability matters more than local working hours |
| The schedule was removed and the instance stayed stopped | delete removes the schedule, not the instance state | Start the instance manually; nothing is left to start it |
| A requires-import error on first apply | a schedule already exists on the instance | Expected, and better than overwriting. terraform import it |
azurerm_mssql_managed_instance_start_stop_schedule- Stop and start an instance — Azure SQL Managed Instance
Microsoft.Sql/managedInstances/startStopSchedulestemplate reference- Sibling modules:
terraform-azurerm-mssql-managed-instance,terraform-azurerm-mssql-managed-instance-failover-group,terraform-azurerm-mssql-managed-instance-active-directory-administrator,terraform-azurerm-mssql-managed-instance-transparent-data-encryption,terraform-azurerm-mssql-server - This module's
SCOPE.md
💙 "Infrastructure as Code should be standardized, consistent, and secure."