mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-15 03:18:07 +00:00
add instance_id generated at install time (#245)
This commit is contained in:
@ -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
|
||||
|
@ -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(),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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(),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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(),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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(),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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(),
|
||||
)
|
||||
)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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()
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
Reference in New Issue
Block a user