add instance_id generated at install time (#245)

This commit is contained in:
bmc-msft
2020-11-02 14:27:51 -05:00
committed by GitHub
parent 89ebc7be50
commit 6c598773dd
20 changed files with 83 additions and 21 deletions

View File

@ -66,6 +66,7 @@ The following describes the information sent to Microsoft if telemetry is enable
The following are common data types used in multiple locations:
* Instance ID - A randomly generated GUID used to uniquely identify an instance of OneFuzz
* Task ID - A randomly generated GUID used to uniquely identify a fuzzing task.
* Job ID - A randomly generated GUID used to uniquely identify a job.
* Machine ID - A GUID used to identify the machine running the task. When run in

View File

@ -64,6 +64,7 @@ pub fn run(args: &clap::ArgMatches) -> Result<()> {
telemetry_key: None,
job_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(),
task_id: Uuid::parse_str("11111111-1111-1111-1111-111111111111").unwrap(),
instance_id: Uuid::parse_str("22222222-2222-2222-2222-222222222222").unwrap(),
},
};

View File

@ -64,6 +64,7 @@ pub fn run(args: &clap::ArgMatches) -> Result<()> {
telemetry_key: None,
job_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(),
task_id: Uuid::parse_str("11111111-1111-1111-1111-111111111111").unwrap(),
instance_id: Uuid::parse_str("22222222-2222-2222-2222-222222222222").unwrap(),
},
};

View File

@ -60,6 +60,7 @@ pub fn run(args: &clap::ArgMatches) -> Result<()> {
telemetry_key: None,
job_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(),
task_id: Uuid::parse_str("11111111-1111-1111-1111-111111111111").unwrap(),
instance_id: Uuid::parse_str("22222222-2222-2222-2222-222222222222").unwrap(),
},
};

View File

@ -62,6 +62,7 @@ pub fn run(args: &clap::ArgMatches) -> Result<()> {
telemetry_key: None,
job_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(),
task_id: Uuid::parse_str("11111111-1111-1111-1111-111111111111").unwrap(),
instance_id: Uuid::parse_str("22222222-2222-2222-2222-222222222222").unwrap(),
},
};

View File

@ -26,6 +26,8 @@ pub struct CommonConfig {
pub task_id: Uuid,
pub instance_id: Uuid,
pub instrumentation_key: Option<Uuid>,
pub heartbeat_queue: Option<Url>,
@ -127,6 +129,7 @@ impl Config {
telemetry::set_property(EventData::TaskId(self.common().task_id));
telemetry::set_property(EventData::MachineId(get_machine_id().await?));
telemetry::set_property(EventData::Version(env!("ONEFUZZ_VERSION").to_string()));
telemetry::set_property(EventData::InstanceId(self.common().instance_id));
if let Ok(scaleset) = get_scaleset_name().await {
telemetry::set_property(EventData::ScalesetId(scaleset));
}

View File

@ -28,6 +28,8 @@ pub struct StaticConfig {
pub telemetry_key: Option<Uuid>,
pub heartbeat_queue: Option<Url>,
pub instance_id: Uuid,
}
// Temporary shim type to bridge the current service-provided config.
@ -44,6 +46,8 @@ struct RawStaticConfig {
pub telemetry_key: Option<Uuid>,
pub heartbeat_queue: Option<Url>,
pub instance_id: Uuid,
}
impl StaticConfig {
@ -70,6 +74,7 @@ impl StaticConfig {
instrumentation_key: config.instrumentation_key,
telemetry_key: config.telemetry_key,
heartbeat_queue: config.heartbeat_queue,
instance_id: config.instance_id,
};
Ok(config)

View File

@ -120,6 +120,7 @@ fn load_config(opt: RunOpt) -> Result<StaticConfig> {
}
async fn run_agent(config: StaticConfig) -> Result<()> {
telemetry::set_property(EventData::InstanceId(config.instance_id));
telemetry::set_property(EventData::MachineId(get_machine_id().await?));
telemetry::set_property(EventData::Version(env!("ONEFUZZ_VERSION").to_string()));
if let Ok(scaleset) = get_scaleset_name().await {

View File

@ -43,6 +43,7 @@ impl Event {
#[derive(Clone, Debug, PartialEq)]
pub enum EventData {
WorkerId(u64),
InstanceId(Uuid),
JobId(Uuid),
TaskId(Uuid),
ScalesetId(String),
@ -77,6 +78,7 @@ impl EventData {
pub fn as_values(&self) -> (&str, String) {
match self {
Self::Version(x) => ("version", x.to_string()),
Self::InstanceId(x) => ("instance_id", x.to_string()),
Self::JobId(x) => ("job_id", x.to_string()),
Self::TaskId(x) => ("task_id", x.to_string()),
Self::ScalesetId(x) => ("scaleset_id", x.to_string()),
@ -113,6 +115,7 @@ impl EventData {
// TODO: Request CELA review of Version, as having this for central stats
// would be useful to track uptake of new releases
Self::Version(_) => false,
Self::InstanceId(_) => true,
Self::TaskId(_) => true,
Self::JobId(_) => true,
Self::MachineId(_) => true,

View File

@ -9,6 +9,7 @@ from onefuzztypes.responses import Info
from ..onefuzzlib.azure.creds import (
get_base_region,
get_base_resource_group,
get_instance_id,
get_subscription,
)
from ..onefuzzlib.request import ok
@ -22,5 +23,6 @@ def main(req: func.HttpRequest) -> func.HttpResponse:
region=get_base_region(),
subscription=get_subscription(),
versions=versions(),
instance_id=get_instance_id(),
)
)

View File

@ -6,7 +6,7 @@
import datetime
import os
import urllib.parse
from typing import Any, Dict, Optional, Union, cast
from typing import Dict, Optional, Union, cast
from azure.common import AzureHttpError, AzureMissingResourceHttpError
from azure.storage.blob import BlobPermissions, ContainerPermissions
@ -129,11 +129,11 @@ def save_blob(
def get_blob(
container: str, name: str, account_id: Optional[str] = None
) -> Optional[Any]: # should be bytes
) -> Optional[bytes]:
service = get_blob_service(account_id)
try:
blob = service.get_blob_to_bytes(container, name).content
return blob
return cast(bytes, blob)
except AzureMissingResourceHttpError:
return None

View File

@ -102,6 +102,16 @@ def get_instance_url() -> str:
return "https://%s.azurewebsites.net" % get_instance_name()
@cached
def get_instance_id() -> UUID:
from .containers import get_blob
blob = get_blob("base-config", "instance_id", account_id=get_func_storage())
if blob is None:
raise Exception("missing instance_id")
return UUID(blob.decode())
DAY_IN_SECONDS = 60 * 60 * 24

View File

@ -12,7 +12,7 @@ from onefuzztypes.models import AgentConfig, ReproConfig
from onefuzztypes.primitives import Extension, Region
from .azure.containers import get_container_sas_url, get_file_sas_url, save_blob
from .azure.creds import get_func_storage, get_instance_url
from .azure.creds import get_func_storage, get_instance_id, get_instance_url
from .azure.monitor import get_monitor_settings
from .azure.queue import get_queue_sas
from .reports import get_report
@ -100,6 +100,7 @@ def build_pool_config(pool_name: str) -> str:
add=True,
),
telemetry_key=os.environ.get("ONEFUZZ_TELEMETRY"),
instance_id=get_instance_id(),
)
save_blob(

View File

@ -5,7 +5,7 @@
import json
import logging
from typing import Optional
from typing import Optional, Union
from onefuzztypes.models import Report
from pydantic import ValidationError
@ -13,7 +13,9 @@ from pydantic import ValidationError
from .azure.containers import get_blob
def parse_report(content: str, metadata: Optional[str] = None) -> Optional[Report]:
def parse_report(
content: Union[str, bytes], metadata: Optional[str] = None
) -> Optional[Report]:
if isinstance(content, bytes):
try:
content = content.decode()

View File

@ -12,7 +12,12 @@ from onefuzztypes.enums import Compare, ContainerPermission, ContainerType, Task
from onefuzztypes.models import TaskConfig, TaskDefinition, TaskUnitConfig
from ..azure.containers import blob_exists, container_exists, get_container_sas_url
from ..azure.creds import get_func_storage, get_fuzz_storage, get_instance_url
from ..azure.creds import (
get_func_storage,
get_fuzz_storage,
get_instance_id,
get_instance_url,
)
from ..azure.queue import get_queue_sas
from .defs import TASK_DEFINITIONS
@ -187,6 +192,7 @@ def build_task_config(
add=True,
),
back_channel_address="https://%s/api/back_channel" % (get_instance_url()),
instance_id=get_instance_id(),
)
if definition.monitor_queue:

View File

@ -15,6 +15,7 @@ from onefuzztypes.responses import BoolResult
from ..onefuzzlib.azure.creds import (
get_base_region,
get_func_storage,
get_instance_id,
get_instance_url,
get_regions,
)
@ -35,6 +36,7 @@ def set_config(pool: Pool) -> Pool:
account_id=get_func_storage(),
add=True,
),
instance_id=get_instance_id(),
)
return pool

View File

@ -63,8 +63,7 @@
"namespace": "onefuzz",
"members": {
"severitiesAtMostInfo": {
"parameters": [
],
"parameters": [],
"output": {
"type": "array",
"value": [
@ -209,8 +208,7 @@
],
"linuxFxVersion": "Python|3.7",
"alwaysOn": true,
"defaultDocuments": [
],
"defaultDocuments": [],
"httpLoggingEnabled": true,
"logsDirectorySizeLimit": 100,
"detailedErrorLoggingEnabled": true,
@ -243,8 +241,7 @@
"type": "Microsoft.Web/serverFarms",
"location": "[resourceGroup().location]",
"kind": "linux",
"dependsOn": [
],
"dependsOn": [],
"properties": {
"name": "[parameters('name')]",
"reserved": true
@ -394,7 +391,6 @@
"properties": {
"workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', variables('monitorAccountName'))]"
},
"plan": {
"name": "[concat('VMInsights', '(', variables('monitorAccountName'), ')')]",
"publisher": "Microsoft",
@ -694,20 +690,17 @@
{
"flag": "ServiceMode",
"value": "Serverless",
"properties": {
}
"properties": {}
},
{
"flag": "EnableConnectivityLogs",
"value": "True",
"properties": {
}
"properties": {}
},
{
"flag": "EnableMessagingLogs",
"value": "False",
"properties": {
}
"properties": {}
}
]
}

View File

@ -92,6 +92,7 @@ FUNC_TOOLS_ERROR = (
logger = logging.getLogger("deploy")
def gen_guid():
return str(uuid.uuid4())
@ -464,6 +465,29 @@ class Client:
% json.dumps(result.as_dict(), indent=4, sort_keys=True),
)
def add_instance_id(self):
logger.info("setting instance_id log export")
container_name = "base-config"
blob_name = "instance_id"
account_name = self.results["deploy"]["func-name"]["value"]
key = self.results["deploy"]["func-key"]["value"]
account_url = "https://%s.blob.core.windows.net" % account_name
client = BlobServiceClient(account_url, credential=key)
if container_name not in [x["name"] for x in client.list_containers()]:
client.create_container(container_name)
blob_client = client.get_blob_client(container_name, blob_name)
if blob_client.exists():
logger.debug("instance_id already exists")
instance_id = uuid.UUID(blob_client.download_blob().readall())
else:
logger.debug("creating new instance_id")
instance_id = uuid.uuid4()
blob_client.upload_blob(str(instance_id))
logger.info("instance_id: %s", instance_id)
def add_log_export(self):
if not self.export_appinsights:
logger.info("not exporting appinsights")
@ -683,6 +707,7 @@ def main():
("queues", Client.create_queues),
("eventgrid", Client.create_eventgrid),
("tools", Client.upload_tools),
("add_instance_id", Client.add_instance_id),
("instance-specific-setup", Client.upload_instance_setup),
("third-party", Client.upload_third_party),
("api", Client.deploy_app),

View File

@ -270,9 +270,11 @@ class AgentConfig(BaseModel):
heartbeat_queue: Optional[str]
instrumentation_key: Optional[str]
telemetry_key: Optional[str]
instance_id: UUID
class TaskUnitConfig(BaseModel):
instance_id: UUID
job_id: UUID
task_id: UUID
task_type: TaskType

View File

@ -4,6 +4,7 @@
# Licensed under the MIT License.
from typing import Dict, Optional
from uuid import UUID
from pydantic import BaseModel
@ -35,6 +36,7 @@ class Info(BaseResponse):
region: Region
subscription: str
versions: Dict[str, Version]
instance_id: Optional[UUID]
class ContainerInfoBase(BaseResponse):