حالات الاختبار لقوالب ARM

توضح هذه المقالة الاختبارات التي يتم تشغيلها باستخدام مجموعة أدوات اختبار القالب لقوالب Azure Resource Manager (قوالب ARM). وتوفر أمثلة على اجتياز الاختبار أو فشله ويتضمن اسم كل اختبار. لمزيدٍ من المعلومات حول كيفية إجراء الاختبارات أو كيفية إجراء اختبار معين، راجع Test parameters.

استخدام المخطط الصحيح

اسم الاختبار: المخطط DeploymentTemplate هو المخطط الصحيح

في قالبك، يجب تحديد قيمة مخطط صالحة.

فشل المثال التالي لأن المخطط غير صالح.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-01-01/deploymentTemplate.json#",
}

يعرض المثال التالي تحذيراً لأنه تم إهمال الإصدار 2015-01-01 للمخطط ولا تتم صيانته الآن.

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
}

مر المثال التالي نظراً لاستخدام مخطط صالح.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
}

يجب تعيين خاصية schema القالب إلى أحد المخططات التالية:

  • https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#
  • https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#
  • https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#
  • https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#
  • https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json

يلزم استخدام المعلمات المعلنة

اسم الاختبار: يجب الرجوع إلى المعلمات

يبحث هذا الاختبار عن المعلمات غير المستخدمة في القالب أو المعلمات التي لم يتم استخدامها في تعبير صالح.

لتقليل التشويش في القالب، احذف أية معلمات تم تعريفها ولكن لا يتم استخدامها. يؤدي التخلص من المعلمات غير المستخدمة إلى تبسيط عمليات نشر القوالب لأنك لست مضطراً إلى توفير قيم غير ضرورية.

في Bicep، استخدم قاعدة Linter - لا توجد معلمات غير مستخدمة.

فشل المثال التالي نظراً لافتقاد التعبير الذي يشير إلى معلمة إلى القوس المربع البادئ ([).

"resources": [
  {
    "location": " parameters('location')]"
  }
]

وقد مر المثال التالي لأن التعبير صالح.

"resources": [
  {
    "location": "[parameters('location')]"
  }
]

لا يمكن احتواء المعلمات الآمنة على تعليمات برمجية افتراضية مضمّنة

اسم الاختبار: لا يمكن أن يكون لمعلمات السلسلة الآمنة قيم افتراضية

لا تقدم قيمة تعليمات برمجية افتراضية مضمّنة لمعلمة آمنة في قالبك. ويمكن أن تحتوي المعلمة الآمنة على سلسلة فارغة كقيمة افتراضية أو تستخدم الدالة newGuid في التعبير.

يمكنك استخدام الأنواع secureString أو secureObject مع المعلمات التي تحتوي على قيم حساسة، مثل كلمات المرور. وعند استخدام معلمة نوع آمن، لا يتم تسجيل قيمة المعلمة أو تخزينها في محفوظات النشر. ويساعد هذا الإجراء على منع المستخدم الضار من اكتشاف القيمة الحساسة.

عند توفير قيمة افتراضية، فإن هذه القيمة يمكن اكتشافها بواسطة أي شخص يمكنه الوصول إلى القالب أو محفوظات النشر.

في Bicep، استخدم قاعدة Linter - المعلمة الآمنة الافتراضية.

المثال التالي يفشل.

"parameters": {
  "adminPassword": {
    "defaultValue": "HardcodedPassword",
    "type": "secureString"
  }
}

مر المثال التالي.

"parameters": {
  "adminPassword": {
    "type": "secureString"
  }
}

وقد مر المثال التالي نظراً لاستخدام الدالة newGuid.

"parameters": {
  "secureParameter": {
    "type": "secureString",
    "defaultValue": "[newGuid()]"
  }
}

لا يمكن أن تكون عناوين URL للبيئة تعليمات برمجية مضمّنة

اسم الاختبار: DeploymentTemplate لا يحتوي على عنوان URL مضمن داخل تعليمة برمجية

لا تُضمن عناوين URL للبيئة داخل تعليمة برمجية في قالبك. يمكنك بدلاً من ذلك استخدم الدالة environment للحصول على عناوين URL بشكل ديناميكي أثناء النشر. للحصول على قائمة بمضيفي عناوين URL المحظورة، راجع حالة الاختبار.

في Bicep، استخدم قاعدة Linter - لا يوجد عنوان URL للبيئة المشفرة.

فشل المثال التالي لأن عنوان URL مضمن داخل التعليمة البرمجية.

"variables":{
  "AzureURL":"https://management.azure.com"
}

كما فشل الاختبار أيضاً عند استخدامه مع concat أو uri.

"variables":{
  "AzureSchemaURL1": "[concat('https://','gallery.azure.com')]",
  "AzureSchemaURL2": "[uri('gallery.azure.com','test')]"
}

مر المثال التالي.

"variables": {
  "AzureSchemaURL": "[environment().gallery]"
}

استخدام الموقع للمعلمة

اسم الاختبار: لا يكون الموقع تعليمة برمجية مضمنة

لتعيين موقع مورد، يجب أن تحتوي قوالبك على معلمة باسم location مع تعيين النوع إلى string. في القالب الرئيسي، azuredeploy.json أو mainTemplate.json، يمكن أن تأخذ هذه المعلمة القيمة الافتراضية لموقع مجموعة الموارد. في القوالب المرتبطة أو المتداخلة، لا يجب أن تأخذ معلمة الموقع "الموقع الافتراضي" كقيمة لها.

قد يكون لمستخدمي القالب وصول محدود إلى المناطق حيث يمكنهم إنشاء الموارد. وقد يمنع موقع المورد المضمن داخل التعليمة البرمجية المستخدمين من إنشاء مورد. قد يمنع التعبير "[resourceGroup().location]" المستخدمين من الوصول إلى منطقة ما، إذا تم إنشاء مجموعة الموارد في منطقة لا يمكن للمستخدم الوصول إليها. ولا يستطيع المستخدمون المحظورون استخدام القالب.

من خلال توفير المعلمة location بأن تكون افتراضية لموقع مجموعة الموارد، يمكن للمستخدمين استخدام القيمة الافتراضية عندما يكون ذلك مناسباً ولكن يمكنهم أيضاً تحديد موقع آخر.

في Bicep، استخدم قاعدة Linter - لا توجد تعبيرات موقع خارج القيم الافتراضية للمعلمة.

فشل المثال التالي نظراً لتعيين location المورد إلى resourceGroup().location.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2021-02-01",
      "name": "storageaccount1",
      "location": "[resourceGroup().location]",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
        "tier": "Premium"
      }
    }
  ]
}

يستخدم المثال التالي المعلمة location ولكنه فشل نظراً لتعيين القيم الافتراضية للمعلمة إلى موقع مضمن داخل تعليمة برمجية.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "westus"
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2021-02-01",
      "name": "storageaccount1",
      "location": "[parameters('location')]",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
        "tier": "Premium"
      }
    }
  ],
  "outputs": {}
}

وقد مر المثال التالي عند استخدام القالب كقالب رئيسي. حيث تم إنشاء معلمة افتراضية لموقع مجموعة الموارد ولكن يسمح للمستخدمين بتوفير قيمة مختلفة.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location for the resources."
      }
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2021-02-01",
      "name": "storageaccount1",
      "location": "[parameters('location')]",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
        "tier": "Premium"
      }
    }
  ],
  "outputs": {}
}

إشعار

إذا تم استخدام المثال السابق كقالب مرتبط، يفشل الاختبار. عند استخدامها كقالب مرتبط، قم بإزالة القيمة الافتراضية.

يجب أن يكون للموارد موقع

اسم الاختبار: يجب أن يكون للموارد موقع

يجب تعيين موقع مورد إلى تعبير قالب أو global. وعادة ما يستخدم تعبير القالب المعلمة location الموضحة في استخدام الموقع للمعلمة.

في Bicep، استخدم قاعدة Linter - لا توجد مواقع مشفرة.

فشل المثال التالي نظراً لأن location ليس تعبيراً أو global.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "functions": [],
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2021-02-01",
      "name": "storageaccount1",
      "location": "westus",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
        "tier": "Premium"
      }
    }
  ],
  "outputs": {}
}

فشل المثال التالي نظراً لتعيين location المورد إلى global.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "functions": [],
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2021-02-01",
      "name": "storageaccount1",
      "location": "global",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
        "tier": "Premium"
      }
    }
  ],
  "outputs": {}
}

وقد مر المثال التالي نظراً لاستخدام المعلمة location تعبيراً. يستخدم location المورد قيمة التعبير.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location for the resources."
      }
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2021-02-01",
      "name": "storageaccount1",
      "location": "[parameters('location')]",
      "kind": "StorageV2",
      "sku": {
        "name": "Premium_LRS",
        "tier": "Premium"
      }
    }
  ],
  "outputs": {}
}

استخدام حجم الجهاز الظاهري للمعلمة

اسم الاختبار: يجب أن يكون حجم الجهاز الظاهري معلمة

لا تقم بتضمين الكائن hardwareProfile بقيمة vmSize داخل التعليمة البرمجية. فشل الاختبار عند حذف hardwareProfile أو عند احتوائها على قيمة داخل التعليمة البرمجية. قم بتوفير معلمة بحيث يمكن لمستخدمي قالبك تعديل حجم الجهاز الظاهري الذي تم نشره. لمزيد من المعلومات، راجع Microsoft.Compute virtualMachines.

فشل المثال التالي نظراً لأن الكائن hardwareProfile بقيمة vmSize مضمن داخل التعليمة البرمجية.

"resources": [
  {
    "type": "Microsoft.Compute/virtualMachines",
    "apiVersion": "2020-12-01",
    "name": "demoVM",
    "location": "[parameters('location')]",
    "properties": {
      "hardwareProfile": {
        "vmSize": "Standard_D2_v3"
      }
    }
  }
]

وقد مر المثال عندما حددت المعلمة قيمة لـ vmSize:

"parameters": {
  "vmSizeParameter": {
    "type": "string",
    "defaultValue": "Standard_D2_v3",
    "metadata": {
      "description": "Size for the virtual machine."
    }
  }
}

ثم استخدم hardwareProfile تعبيراً لـ vmSize وذلك للإشارة إلى قيمة المعلمة:

"resources": [
  {
    "type": "Microsoft.Compute/virtualMachines",
    "apiVersion": "2020-12-01",
    "name": "demoVM",
    "location": "[parameters('location')]",
    "properties": {
      "hardwareProfile": {
        "vmSize": "[parameters('vmSizeParameter')]"
      }
    }
  }
]

قيم الحد الأدنى والحد الأقصى تكون أرقاماً

اسم الاختبار: قيم الحد الأدنى والحد الأقصى تكون أرقاماً

عند تعريف المعلمة باستخدام minValue وmaxValue، حددها كأرقام. يجب استخدام minValue وmaxValue كزوج أو سيفشل الاختبار.

فشل المثال التالي نظراً لأنه تم تحديد قيم minValue وmaxValue كسلاسل.

"exampleParameter": {
  "type": "int",
  "minValue": "0",
  "maxValue": "10"
}

فشل المثال التالي نظراً لأنه تم استخدام minValue فقط.

"exampleParameter": {
  "type": "int",
  "minValue": 0
}

قد مر المثال التالي نظراً لأنه تم تحديد قيم minValue وmaxValue أرقاماً.

"exampleParameter": {
  "type": "int",
  "minValue": 0,
  "maxValue": 10
}

معلمة البيانات الاصطناعية معرفة بشكل صحيح

اسم الاختبار: معلمة البيانات الاصطناعية

عند تضمين معلمات لـ _artifactsLocation و_artifactsLocationSasToken، استخدم الأنواع والإعدادات الافتراضية الصحيحة. ويجب استيفاء الشروط التالية لاجتياز هذا الاختبار:

  • إذا قمت بتوفير معلمة واحدة، يجب توفير الأخرى.
  • يجب أن تكون _artifactsLocation من النوع string.
  • يجب أن يكون لـ _artifactsLocation قيمة افتراضية في القالب الرئيسي.
  • لا ينبغي أن يكون لـ _artifactsLocation قيمة افتراضية في القالب الرئيسي.
  • يجب أن يكون لـ _artifactsLocation إما "[deployment().properties.templateLink.uri]" أو تكون قيمتها الافتراضية "عنوان URL لمستودع بسيط".
  • يجب أن تكون _artifactsLocationSasToken من النوع secureString.
  • يمكن أن تكون القيمة الافتراضية لـ _artifactsLocationSasToken فقط سلسلة فارغة.
  • لا ينبغي أن يكون لـ _artifactsLocationSasToken قيمة افتراضية في القالب الرئيسي.

في Bicep، استخدم قاعدة Linter - معلمات البيانات الاصطناعية.

استخدام المتغيرات المعلنة

اسم الاختبار: الرجوع إلى المعلمات

يبحث هذا الاختبار عن متغيرات غير مستخدمة في القالب أو غير مستخدمة في تعبير صالح. لتقليل التشويش في القالب الخاص بك، احذف أي متغيرات تم تعريفها ولكن لا يتم استخدامها.

يجب الإشارة إلى المتغيرات التي تستخدم عنصر copy لتكرار القيم. للحصول على المزيد من المعلومات، راجع تكرار المتغير في قالب ARM.

في Bicep، استخدم قاعدة Linter - لا توجد متغيرات غير مستخدمة.

فشل المثال التالي نظراً لأنه لا تتم الإشارة إلى المتغير الذي يستخدم العنصر copy.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "itemCount": {
      "type": "int",
      "defaultValue": 5
    }
  },
  "variables": {
    "copy": [
      {
        "name": "stringArray",
        "count": "[parameters('itemCount')]",
        "input": "[concat('item', copyIndex('stringArray', 1))]"
      }
    ]
  },
  "resources": [],
  "outputs": {}
}

فشل المثال التالي نظراً لافتقاد التعبير الذي يشير إلى معلمة إلى القوس المربع البادئ ([).

"outputs": {
  "outputVariable": {
    "type": "string",
    "value": " variables('varExample')]"
  }
}

مر المثال التالي لأنه يُشار إلى المتغير في outputs.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "itemCount": {
      "type": "int",
      "defaultValue": 5
    }
  },
  "variables": {
    "copy": [
      {
        "name": "stringArray",
        "count": "[parameters('itemCount')]",
        "input": "[concat('item', copyIndex('stringArray', 1))]"
      }
    ]
  },
  "resources": [],
  "outputs": {
    "arrayResult": {
      "type": "array",
      "value": "[variables('stringArray')]"
    }
  }
}

وقد مر المثال التالي لأن التعبير صالح.

"outputs": {
  "outputVariable": {
    "type": "string",
    "value": "[variables('varExample')]"
  }
}

لا يستخدم المتغير الديناميكي "concat"

اسم الاختبار: لا تستخدم مراجع المتغير الديناميكي Concat

تحتاج أحياناً إلى تكوين متغير ديناميكياً بناءً على قيمة متغير أو معلمة أخرى. لا تستخدم الدالة concat عند تعيين القيمة. ويمكنك بدلاً من ذلك استخدام عنصر يتضمن الخيارات المتاحة واحصل ديناميكياً على إحدى الخصائص من الكائن أثناء النشر.

مر المثال التالي. يتم تعيين المتغير currentImage ديناميكياً أثناء النشر.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "osType": {
      "type": "string",
      "allowedValues": [
        "Windows",
        "Linux"
      ]
    }
  },
  "variables": {
    "imageOS": {
      "Windows": {
        "image": "Windows Image"
      },
      "Linux": {
        "image": "Linux Image"
      }
    },
    "currentImage": "[variables('imageOS')[parameters('osType')].image]"
  },
  "resources": [],
  "outputs": {
    "result": {
      "type": "string",
      "value": "[variables('currentImage')]"
    }
  }
}

استخدم إصدار واجهة برمجة التطبيقات حديث

اسم الاختبار: يجب أن apiVersions حديثاً

يجب أن يستخدم إصدار واجهة برمجة التطبيقات لكل مورد إصداراً حديثاً ويكون تعليمات برمجية مضمّنة كسلسلة. يُقيم الاختبار بتقييم إصدار واجهة برمجة التطبيقات في القالب مقابل إصدارات موفر المورد في ذاكرة التخزين المؤقت الخاصة بمجموعة الأدوات. يُعد إصدار واجهة برمجة التطبيقات الذي يقل عمره عن عامين من تاريخ تشغيل الاختبار حديثاً. ولا تستخدم الإصدار الأولي عندما يتوفر إصدار أحدث.

يشير التحذير من عدم العثور على إصدار واجهة برمجة التطبيقات فقط إلى أن الإصدار غير مدرج في ذاكرة التخزين المؤقت لمجموعة الأدوات. ويمكنك إنشاء التحذير باستخدام أحدث إصدار من واجهة برمجة التطبيقات، وهذا هو المستحسن.

تعرف على المزيد حول ذاكرة التخزين المؤقت لمجموعة الأدوات.

في Bicep، استخدم قاعدة Linter - استخدم إصدارات واجهة برمجة التطبيقات الأخيرة.

فشل المثال التالي نظراً لأن إصدار واجهة برمجة التطبيقات مر عليه أكثر من عامين.

"resources": [
  {
    "type": "Microsoft.Storage/storageAccounts",
    "apiVersion": "2019-06-01",
    "name": "storageaccount1",
    "location": "[parameters('location')]"
  }
]

فشل المثال التالي نظراً لأنه يتم استخدام إصدار أولي في حين أنه قد توفر إصداراً أحدث.

"resources": [
  {
    "type": "Microsoft.Storage/storageAccounts",
    "apiVersion": "2020-08-01-preview",
    "name": "storageaccount1",
    "location": "[parameters('location')]"
  }
]

مر المثال التالي نظراً لأنه إصدار حديث ليس إصداراً أولياً.

"resources": [
  {
    "type": "Microsoft.Storage/storageAccounts",
    "apiVersion": "2021-02-01",
    "name": "storageaccount1",
    "location": "[parameters('location')]"
  }
]

استخدام إصدار واجهة برمجة التطبيقات المضمن داخل تعليمات برمجية مضمّنة

اسم الاختبار: لا يُسمح بموفري apiVersions

يحدد إصدار واجهة برمجة التطبيقات لنوع مورد الخصائص المتوفرة. ويوفر إصدار واجهة برمجة التطبيقات المضمن داخل تعليمات برمجية مضمّنة في قالبك. لا تقم باسترداد إصدار واجهة برمجة التطبيقات الذي يتم تحديده أثناء النشر لأنك لن تعرف الخصائص المتوفرة.

المثال التالي يفشل.

"resources": [
  {
    "type": "Microsoft.Compute/virtualMachines",
    "apiVersion": "[providers('Microsoft.Compute', 'virtualMachines').apiVersions[0]]",
    ...
  }
]

مر المثال التالي.

"resources": [
  {
    "type": "Microsoft.Compute/virtualMachines",
    "apiVersion": "2020-12-01",
    ...
  }
]

لا تكون الخصائص فارغة

اسم الاختبار: لا يحتوي القالب على فراغات

لا تُعين خصائص التعليمات البرمجية المضمنة إلى قيمة فارغة. تتضمن القيم null وسلاسل وكائنات أو مصفوفات فارغة. وإذا تم تعيين خاصية إلى قيمة فارغة، قم بإزالة تلك الخاصية من القالب. ويمكنك تعيين خاصية إلى قيمة فارغة أثناء النشر، من خلال معلمة.

يمكن أن تتضمن الخاصية template الموجودة في قالب متداخل خصائص فارغة. لمزيد من المعلومات حول القوالب المتداخلة، راجع عمليات نشر Microsoft.Resources.

فشل المثال التالي لوجود خصائص فارغة.

"resources": [
  {
    "type": "Microsoft.Storage/storageAccounts",
    "apiVersion": "2021-01-01",
    "name": "storageaccount1",
    "location": "[parameters('location')]",
    "sku": {},
    "kind": ""
  }
]

وقد مر المثال التالي نظراً لأن الخصائص تتضمن قيماً.

"resources": [
  {
    "type": "Microsoft.Storage/storageAccounts",
    "apiVersion": "2021-01-01",
    "name": "storageaccount1",
    "location": "[parameters('location')]",
    "sku": {
      "name": "Standard_LRS",
      "tier": "Standard"
    },
    "kind": "Storage"
  }
]

استخدام دوال معرف المورد

اسم الاختبار: المعرفات مشتقة من ResourceIDs

عند تحديد معرف مورد، استخدم إحدى دوال معرف المورد. وفيما يلي الدوال المسموح:

لا تستخدم الدالة concat لإنشاء معرف مورد.

في Bicep، استخدم قاعدة Linter - استخدم وظائف معرف المورد.

المثال التالي يفشل.

"networkSecurityGroup": {
    "id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/networkSecurityGroups/', variables('networkSecurityGroupName'))]"
}

مر المثال التالي.

"networkSecurityGroup": {
    "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"
}

دالة ResourceId لها معلمات صحيحة

اسم الاختبار: لا تتضمن ResourceIds

عند إنشاء معرفات الموارد، لا تستخدم دوال غير ضرورية للمعلمات الاختيارية. وبشكل افتراضي، تستخدم الدالة resourceId مجموعة الموارد والاشتراك الحالي. ولا تحتاج إلى توفير هذه القيم.

فشل المثال التالي نظراً لأنك لا تحتاج إلى توفير اسم مجموعة الموارد ومعرف الاشتراك الحالي.

"networkSecurityGroup": {
    "id": "[resourceId(subscription().subscriptionId, resourceGroup().name, 'Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"
}

مر المثال التالي.

"networkSecurityGroup": {
    "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"
}

ينطبق هذا الاختبار على:

بالنسبة لـ reference وlist*، فشل الاختبار عند استخدامها concat لإنشاء معرف المورد.

أفضل ممارسات dependsOn

اسم الاختبار: أفضل ممارسات DependsOn

عند تعيين تبعيات النشر، لا تستخدم الدالة if لاختبار شرط. إذا كان أحد الموارد يعتمد على مورد تم نشره بشروط، فقم بتعيين التبعية كما تفعل مع أي مورد. عندما لا يتم نشر مورد شرطي، يقوم Azure Resource Manager بإزالتها تلقائياً من التبعيات المطلوبة.

لا يمكن أن يبدأ العنصر dependsOn بدالة concat.

في Bicep، استخدم قاعدة Linter - لا توجد إدخالات dependsOn غير ضرورية.

فشل المثال التالي نظراً لأنه يحتوي على دالة if.

"dependsOn": [
  "[if(equals(parameters('newOrExisting'),'new'), variables('storageAccountName'), '')]"
]

فشل المثال التالي نظراً لأنه يبدأ بدالة concat.

"dependsOn": [
  "[concat(variables('storageAccountName'))]"
]

مر المثال التالي.

"dependsOn": [
  "[variables('storageAccountName')]"
]

لا يمكن استخدام التصحيح في عمليات النشر المتداخلة أو المرتبطة التصحيح

اسم الاختبار: لا يتم تصحيح الأخطاء في موارد النشر

عند تعريف قالب متداخل أو مرتبط باستخدام نوع المورد Microsoft.Resources/deployments، يمكنك تمكين تصحيح الأخطاء. يتم استخدام تصحيح الأخطاء عند الحاجة إلى اختبار قالب ولكن يمكن أن يعرض معلومات حساسة. قبل استخدام القالب في بيئة التشغيل، قم بإيقاف تشغيل تصحيح الأخطاء. يمكنك إزالة الكائن debugSetting أو تغيير خاصية detailLevel إلى none.

المثال التالي يفشل.

"debugSetting": {
  "detailLevel": "requestContent"
}

مر المثال التالي.

"debugSetting": {
  "detailLevel": "none"
}

لا تكون أسماء المستخدمين المسؤولين قيمة حرفية

اسم الاختبار: لا يكون adminUsername قيمة حرفية

عند تعيين adminUserName، لا تستخدم قيمة حرفية. إنشاء معلمة لاسم المستخدم واستخدام تعبير للإشارة إلى قيمة المعلمة.

في Bicep، استخدم قاعدة Linter - يجب ألا يكون اسم مستخدم المسؤول حرفيا.

فشل المثال التالي نظراً للقيمة الحرفية.

"osProfile":  {
  "adminUserName": "myAdmin"
}

وقد مر المثال التالي نظراً لاستخدام تعبير.

"osProfile": {
  "adminUsername": "[parameters('adminUsername')]"
}

استخدام أحدث نسخة جهاز ظاهري

اسم الاختبار: استخدام نُسخ الجهاز الظاهري لأحدث إصدار

تم تعطيل هذا الاختبار، ولكن تُظهر المخرجات أنه قد مرّ. تُعد أفضل الممارسات بمثابة آلية تحقيق قالبك للمعايير التالية:

إذا كان قالبك يتضمن جهازاً ظاهرياً من نسخة، فتأكد من أنه يستخدم أحدث إصدار من النسخة.

في Bicep، استخدم قاعدة Linter - استخدم صورة الجهاز الظاهري الثابتة.

استخدام نُسخ جهاز ظاهري مستقرة

اسم الاختبار: لا تعمل الأجهزة الظاهرية بإصدار أولى

لا يجب أن تستخدم الأجهزة الظاهرية نُسخ الإصدار الأولي. يتحقق الاختبار من storageProfile للتحقق من أن imageReference لا يستخدم سلسلة تحتوي على إصدار أولي. ولا يتم استخدام الإصدار الأولي في الخصائص imageReference بالقيم offer وsku أو version.

لمزيد من المعلومات حول خاصية imageReference، راجع Microsoft.Compute virtualMachines وMicrosoft.Compute VirtualMachineScaleSets.

في Bicep، استخدم قاعدة Linter - استخدم صورة الجهاز الظاهري الثابتة.

فشل المثال التالي نظراً لأن imageReference تأخذ قيمة سلسلة تحتوي على إصدار أولي.

"properties": {
  "storageProfile": {
    "imageReference": "latest-preview"
  }
}

فشل المثال التالي عند استخدام إصدار أولي في offer وsku أو version.

"properties": {
  "storageProfile": {
    "imageReference": {
      "publisher": "Canonical",
      "offer": "UbuntuServer_preview",
      "sku": "16.04-LTS-preview",
      "version": "preview"
    }
  }
}

مر المثال التالي.

"storageProfile": {
  "imageReference": {
    "publisher": "Canonical",
    "offer": "UbuntuServer",
    "sku": "16.04-LTS",
    "version": "latest"
  }
}

عدم استخدام ملحق ManagedIdentity

اسم الاختبار: عدم استخدام ملحق ManagedIdentity

لا تقم بتطبيق الملحق ManagedIdentity على جهاز ظاهري. تم إهمال الملحق في عام 2019 ويجب عدم استخدامه بعد الآن.

عدم تضمين المخرجات أسراراً

اسم الاختبار: عدم تضمين المخرجات أسراراً

لا تقم بتضمين أي قيم في القسم outputs الذي قد يكشف الأسرار. على سبيل المثال، معلمات آمنة من النوع secureString أو secureObject، أو الدوال list* مثل listKeys.

يتم تخزين المخرجات من القالب في محفوظات النشر، بحيث لا يمكن للمستخدم الضار العثور على هذه المعلومات.

في Bicep، استخدم قاعدة Linter - يجب ألا تحتوي المخرجات على أسرار.

فشل المثال التالي لأنه يتضمن معلمة آمنة في قيمة الإخراج.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "secureParam": {
      "type": "secureString"
    }
  },
  "functions": [],
  "variables": {},
  "resources": [],
  "outputs": {
    "badResult": {
      "type": "string",
      "value": "[concat('this is the value ', parameters('secureParam'))]"
    }
  }
}

فشل المثال التالي نظراً لأنه يستخدم دالة list* في المخرجات.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "storageName": {
      "type": "string"
    }
  },
  "functions": [],
  "variables": {},
  "resources": [],
  "outputs": {
    "badResult": {
      "type": "object",
      "value": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2021-02-01')]"
    }
  }
}

استخدام protectedSettings لأسرار commandToExecute

اسم الاختبار: استخدام CommandToExecute لـ ProtectedSettings للحصول على الأسرار

بالنسبة إلى الموارد من النوع CustomScript، استخدم protectedSettings المشفر عندما يتضمن commandToExecute بيانات سرية مثل كلمة المرور. على سبيل المثال، يمكن استخدام البيانات السرية في معاملات آمنة من النوع secureString أو secureObject، ودوال list* مثل listKeys أو البرامج النصية المخصصة.

ولا تستخدم البيانات السرية في الكائن settings لأنه يستخدم نصاً واضحاً. لمزيد من المعلومات، راجع Microsoft.Compute virtualMachines/extension أو Windows أو Linux.

في Bicep، استخدم قاعدة Linter - استخدم protectedSettings ل commandToExecute secrets.

فشل المثال التالي نظراً لأن settings يستخدم commandToExecute مع معلمة آمنة.

"parameters": {
  "adminPassword": {
    "type": "secureString"
  }
}
...
"properties": {
  "type": "CustomScript",
  "settings": {
    "commandToExecute": "[parameters('adminPassword')]"
  }
}

فشل المثال التالي نظراً لأن settings يستخدم commandToExecute مستخدماً الدالة listKeys.

"properties": {
  "type": "CustomScript",
  "settings": {
    "commandToExecute": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2021-02-01')]"
  }
}

قد مرّ المثال التالي نظراً لأن protectedSettings يستخدم commandToExecute مستخدماً معلمة آمنة.

"parameters": {
  "adminPassword": {
    "type": "secureString"
  }
}
...
"properties": {
  "type": "CustomScript",
  "protectedSettings": {
    "commandToExecute": "[parameters('adminPassword')]"
  }
}

فشل المثال التالي نظراً لأن protectedSettings يستخدم commandToExecute مستخدماً الدالة listKeys.

"properties": {
  "type": "CustomScript",
  "protectedSettings": {
    "commandToExecute": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageName')), '2021-02-01')]"
  }
}

استخدام إصدارات واجهة برمجة التطبيقات الأحدث في دوال reference

اسم الاختبار: يجب أن تكون apiVersions الأحدث في دوال المرجع

يجب أن يكون إصدار واجهة برمجة التطبيقات المستخدم في دالة reference حديثاً وليس إصداراً أولياً. يُقيم الاختبار بتقييم إصدار واجهة برمجة التطبيقات في القالب مقابل إصدارات موفر المورد في ذاكرة التخزين المؤقت الخاصة بمجموعة الأدوات. يُعد إصدار واجهة برمجة التطبيقات الذي يقل عمره عن عامين من تاريخ تشغيل الاختبار حديثاً.

يشير التحذير من عدم العثور على إصدار واجهة برمجة التطبيقات فقط إلى أن الإصدار غير مدرج في ذاكرة التخزين المؤقت لمجموعة الأدوات. ويمكنك إنشاء التحذير باستخدام أحدث إصدار من واجهة برمجة التطبيقات، وهذا هو المستحسن.

تعرف على المزيد حول ذاكرة التخزين المؤقت لمجموعة الأدوات.

فشل المثال التالي نظراً لأن إصدار واجهة برمجة التطبيقات مر عليه أكثر من عامين.

"outputs": {
  "stgAcct": {
    "type": "string",
    "value": "[reference(resourceId(parameters('storageResourceGroup'), 'Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01')]"
  }
}

فشل المثال التالي نظراً لأن إصدار واجهة برمجة التطبيقات إصدار أولي.

"outputs": {
  "stgAcct": {
    "type": "string",
    "value": "[reference(resourceId(parameters('storageResourceGroup'), 'Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2020-08-01-preview')]"
  }
}

قد مر المثال التالي لأن إصدار واجهة برمجة التطبيقات مر عليه أقل من عامين وليس إصداراً أولياً.

"outputs": {
  "stgAcct": {
    "type": "string",
    "value": "[reference(resourceId(parameters('storageResourceGroup'), 'Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2021-02-01')]"
  }
}

استخدام نوع واسم في دوال resourceId

اسم الاختبار: عدم غموض الموارد

تم تعطيل هذا الاختبار، ولكن تُظهر المخرجات أنه قد مرّ. تُعد أفضل الممارسات بمثابة آلية تحقيق قالبك للمعايير التالية:

يجب أن يتضمن resourceId نوع المورد واسمه. يبحث هذا الاختبار عن جميع دوال القالب resourceId ويتحقق من استخدام المورد في القالب باستخدام البناء الصحيح للجملة. وإلا تعتبر الدالة غامضة.

على سبيل المثال، تعتبر الدالة resourceId غامضة:

  • في حالة عدم العثور على مورد في القالب ولم يتم تحديد مجموعة موارد.
  • إذا كان المورد يتضمن شرطاً ولم يتم تحديد مجموعة موارد.
  • إذا كان تضمن مورد مرتبطاً ببعض مقاطع الاسم وليس كلها. على سبيل المثال، يحتوي مورد تابع على أكثر من مقطع لاسم واحد. لمزيد من المعلومات، راجع ملاحظات على resourceId.

استخدام النطاق الداخلي للمعلمات الآمنة للنشر المتداخل

اسم الاختبار: المعلمات الآمنة في عمليات النشر المتداخلة

استخدم كائن القالب المتداخل expressionEvaluationOptions مع النطاق inner لتقييم التعبيرات التي تحتوي على معلمات آمنة من النوع secureString أو secureObject أو دوال list* مثل listKeys. إذا تم استخدام النطاق outer، يتم تقييم التعبيرات في نص واضح ضمن نطاق القالب الأصلي. وتصبح القيمة الآمنة بعد ذلك مرئية لأي شخص لديه حق الوصول إلى محفوظات النشر. وتكون القيمة الافتراضية لـ expressionEvaluationOptions هي outer.

لمزيد من المعلومات حول القوالب المتداخلة، راجع عمليات نشر Microsoft.Resources ونطاق تقييم التعبير في القوالب المتداخلة.

في Bicep، استخدم قاعدة Linter - المعلمات الآمنة في التوزيع المتداخل.

فشل المثال التالي نظراً لأن expressionEvaluationOptions يستخدم نطاق outer لتقييم معلمات آمنة أو دوال list*.

"resources": [
  {
    "type": "Microsoft.Resources/deployments",
    "apiVersion": "2021-04-01",
    "name": "nestedTemplate",
    "properties": {
      "expressionEvaluationOptions": {
        "scope": "outer"
      }
    }
  }
]

فشل المثال التالي نظراً لأن expressionEvaluationOptions يستخدم نطاق inner لتقييم معلمات آمنة أو دوال list*.

"resources": [
  {
    "type": "Microsoft.Resources/deployments",
    "apiVersion": "2021-04-01",
    "name": "nestedTemplate",
    "properties": {
      "expressionEvaluationOptions": {
        "scope": "inner"
      }
    }
  }
]

الخطوات التالية