Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 10563] ファイルの概要

このコミットは、Goプロジェクトのダッシュボードシステムにおける、ビルダ名の処理に関するバグ修正と堅牢性向上を目的としています。具体的には、異常な形式のビルダ名がシステムに渡された際に、ダッシュボードが正常に動作しなくなる問題を解決します。

コミット

commit c0a53bbc4ac041e0f547c46bf244196eab3caef9
Author: David Symonds <dsymonds@golang.org>
Date:   Thu Dec 1 16:37:30 2011 +1100

    dashboard: don't choke on weird builder names.

    R=adg
    CC=golang-dev
    https://golang.org/cl/5447060

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/c0a53bbc4ac041e0f547c46bf244196eab3caef9

元コミット内容

dashboard: don't choke on weird builder names.

R=adg
CC=golang-dev
https://golang.org/cl/5447060

変更の背景

Goプロジェクトでは、様々なプラットフォームやアーキテクチャでコードのビルドとテストを行うための継続的インテグレーション(CI)システムが稼働しています。このCIシステムは、各ビルドの結果をウェブダッシュボードに表示し、開発者がプロジェクトの健全性を一目で確認できるようにしています。

このダッシュボードは、ビルダ(特定の環境でビルドを実行するエージェント)からの情報を受け取り、それを解析して表示します。ビルダの名前は通常、GOOS-GOARCH(例: linux-amd64, windows-386)のような形式に従っていますが、何らかの理由でこの命名規則から外れた「奇妙な(weird)」または不正な形式のビルダ名がシステムに渡されることがありました。

このコミット以前は、misc/dashboard/godashboard/gobuild.pyスクリプト内のbuilderInfo関数が、このような不正な形式のビルダ名を適切に処理できず、結果としてダッシュボード全体が「choke」(動作停止、エラー発生)してしまう問題がありました。これは、ダッシュボードの可用性と信頼性を損なう重大な問題であり、開発者がビルドの状態を把握できなくなることを意味します。

この変更は、ダッシュボードが不正なビルダ名に対しても堅牢に動作し、エラーで停止することなく、問題のあるビルダを適切にフィルタリングして表示を継続できるようにするために導入されました。

前提知識の解説

  • GoプロジェクトのCI/CDシステム: Go言語のオープンソースプロジェクトは、世界中の様々な貢献者によって開発されています。そのため、コードの品質と互換性を保証するために、広範なテストとビルドプロセスが継続的に実行されています。このプロセスは、GoのCI/CD(継続的インテグレーション/継続的デリバリー)システムによって自動化されています。このシステムは、コミットがプッシュされるたびに、多数の異なるオペレーティングシステム(GOOS)とアーキテクチャ(GOARCH)の組み合わせ(例: Linux/AMD64, Windows/386, macOS/ARM64など)でコードをビルドし、テストを実行します。
  • Goダッシュボード: GoプロジェクトのCI/CDシステムの一部として、ビルドとテストの結果を視覚的に表示するウェブダッシュボードが存在します。このダッシュボードは、各コミットに対するビルドの成功/失敗、テスト結果、パフォーマンスデータなどを集約し、開発者がプロジェクトの健全性をリアルタイムで監視できるようにします。このダッシュボードは、Google App Engine上で動作するPythonアプリケーションとして実装されていました。
  • Google App Engine (GAE): Googleが提供するPaaS(Platform as a Service)であり、ウェブアプリケーションやモバイルバックエンドを構築・ホストするためのプラットフォームです。このコミットで変更されているgobuild.pyは、GAEのPython 2.xランタイムで動作するウェブアプリケーションの一部であり、webappモジュールを使用していることからそれが伺えます。GAEは、スケーラビリティとメンテナンスの容易さを提供しますが、特定のAPIやフレームワークに依存するため、その特性を理解しておく必要があります。
  • ビルダ名(Builder Name): GoのCIシステムにおいて、特定のビルド環境(OSとアーキテクチャの組み合わせ)を識別するために使用される文字列です。慣例的にGOOS-GOARCHの形式(例: linux-amd64, darwin-arm64)で表現されます。このコミットの核心は、この命名規則に従わない「奇妙な」ビルダ名がシステムに混入した場合の処理です。
  • Pythonの文字列分割 (split): Pythonの文字列メソッドsplit()は、指定された区切り文字で文字列を分割し、部分文字列のリストを返します。このコミットでは、ビルダ名をハイフン(-)で分割してGOOSGOARCHを抽出するために使用されています。
  • Pythonのリスト内包表記 (List Comprehension): Pythonの強力な機能の一つで、簡潔な構文でリストを生成できます。このコミットでは、r['builds'] = [b for b in r['builds'] if b['builder'] not in bad_builders]のように、特定の条件を満たす要素のみを含む新しいリストを作成するために使用されています。

技術的詳細

このコミットは、misc/dashboard/godashboard/gobuild.pyファイルに対して行われました。このファイルは、Goプロジェクトのビルドダッシュボードのバックエンドロジックを担うPythonスクリプトです。

変更の核心は、builderInfo関数とMainPageクラスのgetメソッド内のビルダ情報処理の改善です。

  1. builderInfo関数の堅牢性向上:

    • builderInfo(b)関数は、ビルダ名bを受け取り、それをハイフンで分割してGOOSGOARCHを抽出します。
    • 変更前は、f = b.split('-', 3)の結果が期待される要素数(少なくとも2つ)を持たない場合(例: weirdbuilderのようにハイフンを含まない場合)、f[1]にアクセスしようとした際にIndexErrorが発生し、スクリプトがクラッシュする可能性がありました。
    • 追加された行 if len(f) < 2: f.append(None) は、この問題を解決します。splitの結果のリストfの要素数が2未満の場合、Noneをリストに追加することで、f[1]へのアクセスが常に安全に行われるようにします。これにより、不正な形式のビルダ名に対しても、goarchNoneとして扱われ、後続の処理で適切にフィルタリングされるようになります。
  2. MainPageクラスにおける不正なビルダのフィルタリング:

    • MainPageクラスのgetメソッドは、ビルドのリビジョン情報とそれに関連するビルド結果(各ビルダからのものを含む)を処理し、ダッシュボードに表示するためのデータを準備します。
    • 変更前は、for b in r['builds']: builders[b['builder']] = builderInfo(b['builder']) のループ内で、builderInfoがエラーを発生させると、ダッシュボード全体が停止していました。
    • 変更後、まずbuilderInfoの呼び出し結果をbiに格納し、builders辞書に格納する前にb['builder'] in buildersで重複チェックを行うようになりました。これは、同じビルダ名が複数回出現する場合の冗長な処理を避けるためです。
    • 最も重要な変更は、不正なビルダを識別し、それらをデータセットから削除するロジックの追加です。
      • bad_builders = [key for key in builders if not builders[key]['goarch']]builders辞書をイテレートし、goarchNoneである(つまり、builderInfoによって不正な形式と判断された)ビルダ名をbad_buildersリストに収集します。
      • for key in bad_builders: del builders[key]bad_buildersリストに含まれるすべてのビルダをbuilders辞書から削除します。これにより、ダッシュボードに表示されるビルダのリストから不正なものが除外されます。
      • for r in revs: r['builds'] = [b for b in r['builds'] if b['builder'] not in bad_builders]:各リビジョン(revs)のビルド結果(r['builds'])から、bad_buildersリストに含まれるビルダの情報をフィルタリングして削除します。これにより、ダッシュボードの表示データから、不正なビルダに関連するビルド結果が完全に排除されます。
    • values['bad'] = bad_builders:フィルタリングされた不正なビルダのリストをvalues辞書に追加しています。これは、デバッグ目的や、ダッシュボード上で「これらのビルダは不正なため表示されません」といったメッセージを表示するために使用される可能性があります。

これらの変更により、ダッシュボードは不正なビルダ名が入力されてもクラッシュすることなく、それらを適切に無視し、残りの有効なビルド情報を表示し続けることができるようになりました。

コアとなるコードの変更箇所

--- a/misc/dashboard/godashboard/gobuild.py
+++ b/misc/dashboard/godashboard/gobuild.py
@@ -60,6 +60,8 @@ N = 30

  def builderInfo(b):
      f = b.split('-', 3)
+    if len(f) < 2:
+      f.append(None)
      goos = f[0]
      goarch = f[1]
      note = ""
@@ -105,7 +107,15 @@ class MainPage(webapp.RequestHandler):

          for r in revs:
              for b in r['builds']:
-                builders[b['builder']] = builderInfo(b['builder'])
+                if b['builder'] in builders:
+                    continue
+                bi = builderInfo(b['builder'])
+                builders[b['builder']] = bi
+        bad_builders = [key for key in builders if not builders[key]['goarch']]
+        for key in bad_builders:
+            del builders[key]
+        for r in revs:
+            r['builds'] = [b for b in r['builds'] if b['builder'] not in bad_builders]

          for r in revs:
              have = set(x['builder'] for x in r['builds'])
@@ -123,6 +133,7 @@ class MainPage(webapp.RequestHandler):
          if len(results) == num:
              values['next'] = page + 1

+        values['bad'] = bad_builders
          path = os.path.join(os.path.dirname(__file__), 'main.html')
          self.response.out.write(template.render(path, values))

コアとなるコードの解説

  1. builderInfo関数の変更:

    def builderInfo(b):
        f = b.split('-', 3)
        if len(f) < 2:
          f.append(None)
        goos = f[0]
        goarch = f[1]
        note = ""
    
    • f = b.split('-', 3): ビルダ名を最大3つの部分に分割します。例えば、linux-amd64['linux', 'amd64']に、weirdbuilder['weirdbuilder']になります。
    • if len(f) < 2: f.append(None): ここが重要な変更点です。splitの結果、リストfの要素が2つ未満(つまり、ハイフンが1つも含まれていないか、1つしか含まれていないが、goarchが期待される位置にない場合など)の場合、f[1]へのアクセスがIndexErrorを引き起こすのを防ぐために、リストの末尾にNoneを追加します。これにより、goarch = f[1]の行でgoarchNoneに設定され、後続のフィルタリング処理でこのビルダが不正であると識別されるようになります。
  2. MainPageクラスのgetメソッド内の変更:

            for r in revs:
                for b in r['builds']:
                    if b['builder'] in builders:
                        continue
                    bi = builderInfo(b['builder'])
                    builders[b['builder']] = bi
            bad_builders = [key for key in builders if not builders[key]['goarch']]
            for key in bad_builders:
                del builders[key]
            for r in revs:
                r['builds'] = [b for b in r['builds'] if b['builder'] not in bad_builders]
    
    • if b['builder'] in builders: continue: 既に処理済みのビルダはスキップし、重複処理を避けます。
    • bi = builderInfo(b['builder']): 各ビルダ名に対してbuilderInfo関数を呼び出し、その情報を取得します。このbiには、goosgoarch(不正な場合はNone)が含まれます。
    • builders[b['builder']] = bi: 取得したビルダ情報をbuilders辞書に格納します。
    • bad_builders = [key for key in builders if not builders[key]['goarch']]: builders辞書を走査し、goarchNoneである(つまり、builderInfoで不正と判断された)ビルダのキー(名前)をbad_buildersリストに集めます。
    • for key in bad_builders: del builders[key]: bad_buildersリストに含まれるすべてのビルダをbuilders辞書から削除します。これにより、ダッシュボードのビルダ一覧から不正なものが取り除かれます。
    • for r in revs: r['builds'] = [b for b in r['builds'] if b['builder'] not in bad_builders]: 各リビジョンに関連付けられたビルド結果のリストr['builds']を、リスト内包表記を使ってフィルタリングします。bad_buildersリストに含まれるビルダのビルド結果は新しいリストから除外されます。これにより、ダッシュボードに表示される個々のビルド結果からも不正なビルダの情報が排除されます。
    • values['bad'] = bad_builders: 最後に、フィルタリングされた不正なビルダのリストをvalues辞書に追加します。これは、ダッシュボードのテンプレート(main.html)で利用され、例えば「以下のビルダは認識されませんでした: ...」といったメッセージを表示するために使われる可能性があります。

これらの変更により、ダッシュボードは不正なビルダ名が混入しても、エラーで停止することなく、それらを適切に処理し、有効な情報のみを表示し続けることができるようになりました。

関連リンク

参考にした情報源リンク

[インデックス 10563] ファイルの概要

このコミットは、Goプロジェクトのダッシュボードシステムにおける、ビルダ名の処理に関するバグ修正と堅牢性向上を目的としています。具体的には、異常な形式のビルダ名がシステムに渡された際に、ダッシュボードが正常に動作しなくなる問題を解決します。

コミット

commit c0a53bbc4ac041e0f547c46bf244196eab3caef9
Author: David Symonds <dsymonds@golang.org>
Date:   Thu Dec 1 16:37:30 2011 +1100

    dashboard: don't choke on weird builder names.

    R=adg
    CC=golang-dev
    https://golang.org/cl/5447060

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/c0a53bbc4ac041e0f547c46bf244196eab3caef9

元コミット内容

dashboard: don't choke on weird builder names.

R=adg
CC=golang-dev
https://golang.org/cl/5447060

変更の背景

Goプロジェクトでは、様々なプラットフォームやアーキテクチャでコードのビルドとテストを行うための継続的インテグレーション(CI)システムが稼働しています。このCIシステムは、各ビルドの結果をウェブダッシュボードに表示し、開発者がプロジェクトの健全性を一目で確認できるようにしています。

このダッシュボードは、ビルダ(特定の環境でビルドを実行するエージェント)からの情報を受け取り、それを解析して表示します。ビルダの名前は通常、GOOS-GOARCH(例: linux-amd64, windows-386)のような形式に従っていますが、何らかの理由でこの命名規則から外れた「奇妙な(weird)」または不正な形式のビルダ名がシステムに渡されることがありました。

このコミット以前は、misc/dashboard/godashboard/gobuild.pyスクリプト内のbuilderInfo関数が、このような不正な形式のビルダ名を適切に処理できず、結果としてダッシュボード全体が「choke」(動作停止、エラー発生)してしまう問題がありました。これは、ダッシュボードの可用性と信頼性を損なう重大な問題であり、開発者がビルドの状態を把握できなくなることを意味します。

この変更は、ダッシュボードが不正なビルダ名に対しても堅牢に動作し、エラーで停止することなく、問題のあるビルダを適切にフィルタリングして表示を継続できるようにするために導入されました。

前提知識の解説

  • GoプロジェクトのCI/CDシステム: Go言語のオープンソースプロジェクトは、世界中の様々な貢献者によって開発されています。そのため、コードの品質と互換性を保証するために、広範なテストとビルドプロセスが継続的に実行されています。このプロセスは、GoのCI/CD(継続的インテグレーション/継続的デリバリー)システムによって自動化されています。このシステムは、コミットがプッシュされるたびに、多数の異なるオペレーティングシステム(GOOS)とアーキテクチャ(GOARCH)の組み合わせ(例: Linux/AMD64, Windows/386, macOS/ARM64など)でコードをビルドし、テストを実行します。
  • Goダッシュボード: GoプロジェクトのCI/CDシステムの一部として、ビルドとテストの結果を視覚的に表示するウェブダッシュボードが存在します。このダッシュボードは、各コミットに対するビルドの成功/失敗、テスト結果、パフォーマンスデータなどを集約し、開発者がプロジェクトの健全性をリアルタイムで監視できるようにします。このダッシュボードは、Google App Engine上で動作するPythonアプリケーションとして実装されていました。
  • Google App Engine (GAE): Googleが提供するPaaS(Platform as a Service)であり、ウェブアプリケーションやモバイルバックエンドを構築・ホストするためのプラットフォームです。このコミットで変更されているgobuild.pyは、GAEのPython 2.xランタイムで動作するウェブアプリケーションの一部であり、webappモジュールを使用していることからそれが伺えます。GAEは、スケーラビリティとメンテナンスの容易さを提供しますが、特定のAPIやフレームワークに依存するため、その特性を理解しておく必要があります。
  • ビルダ名(Builder Name): GoのCIシステムにおいて、特定のビルド環境(OSとアーキテクチャの組み合わせ)を識別するために使用される文字列です。慣例的にGOOS-GOARCHの形式(例: linux-amd64, darwin-arm64)で表現されます。このコミットの核心は、この命名規則に従わない「奇妙な」ビルダ名がシステムに混入した場合の処理です。
  • Pythonの文字列分割 (split): Pythonの文字列メソッドsplit()は、指定された区切り文字で文字列を分割し、部分文字列のリストを返します。このコミットでは、ビルダ名をハイフン(-)で分割してGOOSGOARCHを抽出するために使用されています。
  • Pythonのリスト内包表記 (List Comprehension): Pythonの強力な機能の一つで、簡潔な構文でリストを生成できます。このコミットでは、r['builds'] = [b for b in r['builds'] if b['builder'] not in bad_builders]のように、特定の条件を満たす要素のみを含む新しいリストを作成するために使用されています。

技術的詳細

このコミットは、misc/dashboard/godashboard/gobuild.pyファイルに対して行われました。このファイルは、Goプロジェクトのビルドダッシュボードのバックエンドロジックを担うPythonスクリプトです。

変更の核心は、builderInfo関数とMainPageクラスのgetメソッド内のビルダ情報処理の改善です。

  1. builderInfo関数の堅牢性向上:

    • builderInfo(b)関数は、ビルダ名bを受け取り、それをハイフンで分割してGOOSGOARCHを抽出します。
    • 変更前は、f = b.split('-', 3)の結果が期待される要素数(少なくとも2つ)を持たない場合(例: weirdbuilderのようにハイフンを含まない場合)、f[1]にアクセスしようとした際にIndexErrorが発生し、スクリプトがクラッシュする可能性がありました。
    • 追加された行 if len(f) < 2: f.append(None) は、この問題を解決します。splitの結果のリストfの要素数が2未満の場合、Noneをリストに追加することで、f[1]へのアクセスが常に安全に行われるようにします。これにより、不正な形式のビルダ名に対しても、goarchNoneとして扱われ、後続の処理で適切にフィルタリングされるようになります。
  2. MainPageクラスにおける不正なビルダのフィルタリング:

    • MainPageクラスのgetメソッドは、ビルドのリビジョン情報とそれに関連するビルド結果(各ビルダからのものを含む)を処理し、ダッシュボードに表示するためのデータを準備します。
    • 変更前は、for b in r['builds']: builders[b['builder']] = builderInfo(b['builder']) のループ内で、builderInfoがエラーを発生させると、ダッシュボード全体が停止していました。
    • 変更後、まずbuilderInfoの呼び出し結果をbiに格納し、builders辞書に格納する前にb['builder'] in buildersで重複チェックを行うようになりました。これは、同じビルダ名が複数回出現する場合の冗長な処理を避けるためです。
    • 最も重要な変更は、不正なビルダを識別し、それらをデータセットから削除するロジックの追加です。
      • bad_builders = [key for key in builders if not builders[key]['goarch']]builders辞書をイテレートし、goarchNoneである(つまり、builderInfoによって不正な形式と判断された)ビルダ名をbad_buildersリストに収集します。
      • for key in bad_builders: del builders[key]bad_buildersリストに含まれるすべてのビルダをbuilders辞書から削除します。これにより、ダッシュボードに表示されるビルダのリストから不正なものが除外されます。
      • for r in revs: r['builds'] = [b for b in r['builds'] if b['builder'] not in bad_builders]:各リビジョン(revs)のビルド結果(r['builds'])から、bad_buildersリストに含まれるビルダの情報をフィルタリングして削除します。これにより、ダッシュボードの表示データから、不正なビルダに関連するビルド結果が完全に排除されます。
    • values['bad'] = bad_builders:フィルタリングされた不正なビルダのリストをvalues辞書に追加しています。これは、デバッグ目的や、ダッシュボード上で「これらのビルダは不正なため表示されません」といったメッセージを表示するために使用される可能性があります。

これらの変更により、ダッシュボードは不正なビルダ名が入力されてもクラッシュすることなく、それらを適切に無視し、残りの有効なビルド情報を表示し続けることができるようになりました。

コアとなるコードの変更箇所

--- a/misc/dashboard/godashboard/gobuild.py
+++ b/misc/dashboard/godashboard/gobuild.py
@@ -60,6 +60,8 @@ N = 30

  def builderInfo(b):
      f = b.split('-', 3)
+    if len(f) < 2:
+      f.append(None)
      goos = f[0]
      goarch = f[1]
      note = ""
@@ -105,7 +107,15 @@ class MainPage(webapp.RequestHandler):

          for r in revs:
              for b in r['builds']:
-                builders[b['builder']] = builderInfo(b['builder'])
+                if b['builder'] in builders:
+                    continue
+                bi = builderInfo(b['builder'])
+                builders[b['builder']] = bi
+        bad_builders = [key for key in builders if not builders[key]['goarch']]
+        for key in bad_builders:
+            del builders[key]
+        for r in revs:
+            r['builds'] = [b for b in r['builds'] if b['builder'] not in bad_builders]

          for r in revs:
              have = set(x['builder'] for x in r['builds'])
@@ -123,6 +133,7 @@ class MainPage(webapp.RequestHandler):
          if len(results) == num:
              values['next'] = page + 1

+        values['bad'] = bad_builders
          path = os.path.join(os.path.dirname(__file__), 'main.html')
          self.response.out.write(template.render(path, values))

コアとなるコードの解説

  1. builderInfo関数の変更:

    def builderInfo(b):
        f = b.split('-', 3)
        if len(f) < 2:
          f.append(None)
        goos = f[0]
        goarch = f[1]
        note = ""
    
    • f = b.split('-', 3): ビルダ名を最大3つの部分に分割します。例えば、linux-amd64['linux', 'amd64']に、weirdbuilder['weirdbuilder']になります。
    • if len(f) < 2: f.append(None): ここが重要な変更点です。splitの結果、リストfの要素が2つ未満(つまり、ハイフンが1つも含まれていないか、1つしか含まれていないが、goarchが期待される位置にない場合など)の場合、f[1]へのアクセスがIndexErrorを引き起こすのを防ぐために、リストの末尾にNoneを追加します。これにより、goarch = f[1]の行でgoarchNoneに設定され、後続のフィルタリング処理でこのビルダが不正であると識別されるようになります。
  2. MainPageクラスのgetメソッド内の変更:

            for r in revs:
                for b in r['builds']:
                    if b['builder'] in builders:
                        continue
                    bi = builderInfo(b['builder'])
                    builders[b['builder']] = bi
            bad_builders = [key for key in builders if not builders[key]['goarch']]
            for key in bad_builders:
                del builders[key]
            for r in revs:
                r['builds'] = [b for b in r['builds'] if b['builder'] not in bad_builders]
    
    • if b['builder'] in builders: continue: 既に処理済みのビルダはスキップし、重複処理を避けます。
    • bi = builderInfo(b['builder']): 各ビルダ名に対してbuilderInfo関数を呼び出し、その情報を取得します。このbiには、goosgoarch(不正な場合はNone)が含まれます。
    • builders[b['builder']] = bi: 取得したビルダ情報をbuilders辞書に格納します。
    • bad_builders = [key for key in builders if not builders[key]['goarch']]: builders辞書を走査し、goarchNoneである(つまり、builderInfoで不正と判断された)ビルダのキー(名前)をbad_buildersリストに集めます。
    • for key in bad_builders: del builders[key]: bad_buildersリストに含まれるすべてのビルダをbuilders辞書から削除します。これにより、ダッシュボードのビルダ一覧から不正なものが取り除かれます。
    • for r in revs: r['builds'] = [b for b in r['builds'] if b['builder'] not in bad_builders]: 各リビジョンに関連付けられたビルド結果のリストr['builds']を、リスト内包表記を使ってフィルタリングします。bad_buildersリストに含まれるビルダのビルド結果は新しいリストから除外されます。これにより、ダッシュボードに表示される個々のビルド結果からも不正なビルダの情報が排除されます。
    • values['bad'] = bad_builders: 最後に、フィルタリングされた不正なビルダのリストをvalues辞書に追加します。これは、ダッシュボードのテンプレート(main.html)で利用され、例えば「以下のビルダは認識されませんでした: ...」といったメッセージを表示するために使われる可能性があります。

これらの変更により、ダッシュボードは不正なビルダ名が混入しても、エラーで停止することなく、それらを適切に処理し、有効な情報のみを表示し続けることができるようになりました。

関連リンク

参考にした情報源リンク